Compare commits

...

95 Commits

Author SHA1 Message Date
99b02b85b4 Android #23 2023-07-29 00:54:24 +00:00
689dc4a17b Merge pull request #11155 from liamwhite/memory3
memory: check page against address space size
2023-07-28 09:29:21 -04:00
9352a0f2e6 Merge pull request #11156 from 8bitDream/localize
android: Only label language with language
2023-07-28 09:29:11 -04:00
b1730d3c72 Merge pull request #11163 from Moonlacer/revert-10946-amdBlending
Revert "Blacklist EDS3 blending from new AMD drivers"
2023-07-28 09:29:00 -04:00
4007142b91 Revert "Blacklist EDS3 blending from new AMD drivers" 2023-07-26 15:02:48 -05:00
a1c355051e Merge pull request #11128 from german77/discord
yuzu: Replace httplib with QtNetworkRequest
2023-07-26 11:04:57 -04:00
d3da1e6517 Merge pull request #10990 from comex/ubsan
Fixes and workarounds to make UBSan happier on macOS
2023-07-26 10:33:28 -04:00
6ffcc3d5d2 Merge pull request #11142 from german77/avoid_crash
yuzu: Avoid reading broken games
2023-07-26 10:33:14 -04:00
01b379fe20 Address feedback 2023-07-26 00:41:24 -04:00
4742627744 Merge pull request #11157 from lat9nq/nasm
cmake: Download nasm from our external repo
2023-07-25 13:35:02 -04:00
43920aa1a0 cmake: Download nasm from our external repo
This package download has intermittent failures due to host Internet
issues (presumably), so download it ourselves from our own hosting.
2023-07-25 15:47:44 -04:00
e2ea46f6ef android: Only label language with language 2023-07-25 10:38:30 -04:00
07f71e2620 memory: check page against address space size 2023-07-25 09:51:06 -04:00
18000df5e9 Merge pull request #11095 from liamwhite/memory2
memory: cleanup
2023-07-24 13:47:11 -04:00
bb0edb53ae Merge pull request #11135 from liamwhite/getaddrinfo
core: implement GetGaiStringErrorRequest, IContextRegistrar
2023-07-24 13:47:02 -04:00
099295d7c6 Merge pull request #11136 from liamwhite/sp3shader
ssa_rewrite_pass: use proper maps
2023-07-24 13:46:53 -04:00
a0ed0e4e10 yuzu: Avoid reading broken games 2023-07-24 08:59:14 -06:00
dad0d076ee ssa_rewrite_pass: use proper maps 2023-07-23 11:38:01 -04:00
3e3294e1c2 core: implement GetGaiStringErrorRequest, IContextRegistrar 2023-07-22 23:29:45 -04:00
9f3f615e05 core: reduce TOCTTOU memory access 2023-07-22 11:19:29 -04:00
d144168442 memory: minimize dependency on process 2023-07-22 11:19:29 -04:00
3e4029b238 Merge pull request #11042 from lat9nq/wayland-appimage
ci/linux: Target deploy script from appimage path
2023-07-22 11:17:48 -04:00
b1aed2c5b7 Merge pull request #11094 from liamwhite/get
kernel: misc cleanup of page table accessors
2023-07-22 11:17:36 -04:00
0ea138fb5b Merge pull request #11098 from GPUCode/texel-buffers
buffer_cache: Increase number of texture buffers
2023-07-22 11:17:27 -04:00
482c957f5d Merge pull request #11113 from liamwhite/nsd1
nsd: add GetApplicationServerEnvironmentType
2023-07-21 21:24:36 -07:00
39edd2ff82 Merge pull request #11129 from liamwhite/dynamic_cast
general: remove uses of dynamic_cast
2023-07-21 21:22:51 -07:00
05bc024260 core: remove remaining uses of dynamic_cast 2023-07-21 19:37:29 -04:00
4bee333d84 general: reduce use of dynamic_cast 2023-07-21 19:22:14 -04:00
c067046387 yuzu: Replace httplib with QtNetworkRequest 2023-07-21 16:53:06 -06:00
efda6cc9ec Merge pull request #11123 from Morph1984/remove-mem-hungry-opts
ci: Remove GA, Gr optimizations from MSVC
2023-07-21 15:06:07 -04:00
8927f016e1 Merge pull request #11069 from lat9nq/mingw-no-tzdb
common: Use arithmetic instead of string ops to get time zone
2023-07-21 15:05:59 -04:00
c0202da9ac Merge pull request #11096 from german77/amiibooo
service: nfc: Update Implementation to match with latest RE
2023-07-21 09:21:48 -04:00
7fc5ef68d2 ci: Remove GA, Gr optimizations from MSVC
Internal testing has shown these result in higher committed memory usage in some systems.
Also Ob2 is already implied by O2, so that can be removed as well.
2023-07-21 01:30:43 -04:00
014ca709c9 Merge pull request #11116 from lat9nq/clang-shadowing
general: Silence -Wshadow{,-uncaptured-local} warnings
2023-07-19 17:14:55 -04:00
86bbfe3b1d Merge pull request #11114 from Kelebek1/warnings
Mark SetIdleTimeDetectionExtension logging as debug
2023-07-19 17:14:45 -04:00
1ab3bd5a5e demangle: Update to llvm/llvm-project@ecbc812e0c 2023-07-18 22:39:26 -04:00
c1e57ad358 CMake: Require LLVM 17 or later
API changes necessitate an update here.
2023-07-18 22:39:13 -04:00
4ecedc4991 vk_buffer_cache: Format 2023-07-18 19:56:20 -04:00
71b3b2a2f0 general: Silence -Wshadow{,-uncaptured-local} warnings
These occur in the latest commits in LLVM Clang.
2023-07-18 19:31:35 -04:00
80cd67ed7b Debug SetIdleTimeDetectionExtension 2023-07-18 10:16:14 +01:00
3fded314f2 Merge pull request #11109 from Morph1984/net
network: Fix compilation with ENABLE_WEB_SERVICE=OFF
2023-07-17 23:57:39 -04:00
8f1d48fda6 nsd: add GetApplicationServerEnvironmentType 2023-07-17 21:34:23 -04:00
16c238e4b9 ssl: Link with crypt32 for secure channel backend 2023-07-17 15:46:24 -04:00
e0fb1d3d17 ssl: Reorder inclusions 2023-07-17 15:46:24 -04:00
5bbc3aef13 network: Forward declarations 2023-07-17 15:36:03 -04:00
54f150b70a service: nfc: Update Implementation to match with latest RE 2023-07-17 11:24:23 -06:00
5593bed08a Merge pull request #10934 from abouvier/cmake-vma
cmake: allow using system VMA library
2023-07-17 10:42:41 -04:00
8750564bd2 Merge pull request #11102 from v1993/your-mom-is-encrypted
android: fix links to re-dumping guides
2023-07-17 10:42:31 -04:00
2461c78e3f Merge pull request #10912 from comex/ssl
Implement SSL service
2023-07-16 16:56:47 -04:00
50fe45f1e4 android: fix links to re-dumping guides 2023-07-16 20:22:27 +03:00
4347dd26c6 buffer_cache: Increase number of texture buffers 2023-07-15 23:09:58 +03:00
d7c532d889 Fixes and workarounds to make UBSan happier on macOS
There are still some other issues not addressed here, but it's a start.

Workarounds for false-positive reports:

- `RasterizerAccelerated`: Put a gigantic array behind a `unique_ptr`,
  because UBSan has a [hardcoded limit](https://stackoverflow.com/questions/64531383/c-runtime-error-using-fsanitize-undefined-object-has-a-possibly-invalid-vp)
  of how big it thinks objects can be, specifically when dealing with
  offset-to-top values used with multiple inheritance.  Hopefully this
  doesn't have a performance impact.

- `QueryCacheBase::QueryCacheBase`: Avoid an operation that UBSan thinks
  is UB even though it at least arguably isn't.  See the link in the
  comment for more information.

Fixes for correct reports:

- `PageTable`, `Memory`: Use `uintptr_t` values instead of pointers to
  avoid UB from pointer overflow (when pointer arithmetic wraps around
  the address space).

- `KScheduler::Reload`: `thread->GetOwnerProcess()` can be `nullptr`;
  avoid calling methods on it in this case.  (The existing code returns
  a garbage reference to a field, which is then passed into
  `LoadWatchpointArray`, and apparently it's never used, so it's
  harmless in practice but still triggers UBSan.)

- `KAutoObject::Close`: This function calls `this->Destroy()`, which
  overwrites the beginning of the object with junk (specifically a free
  list pointer).  Then it calls `this->UnregisterWithKernel()`.  UBSan
  complains about a type mismatch because the vtable has been
  overwritten, and I believe this is indeed UB.  `UnregisterWithKernel`
  also loads `m_kernel` from the 'freed' object, which seems to be
  technically safe (the overwriting doesn't extend as far as that
  field), but seems dubious.  Switch to a `static` method and load
  `m_kernel` in advance.
2023-07-15 12:00:28 -07:00
474db2d8da kernel: reduce page table region checking 2023-07-14 22:33:10 -04:00
a85ce8ea56 k_process: PageTable -> GetPageTable 2023-07-14 21:43:15 -04:00
04868ab9da file_sys/content_archive: Detect compressed NCAs (#11047) 2023-07-12 23:17:18 +02:00
63a0a1f826 time_zone: Clean up includes 2023-07-12 03:03:03 -04:00
9e0d6f7d54 time_zone: Swap subtraction order 2023-07-12 03:02:45 -04:00
13755c0903 time_zone: Account for leap years
Protects against invalid hour offsets during transitions to years
following leap years.
2023-07-12 02:34:02 -04:00
c3050c1b48 cmake: allow using system VMA library 2023-07-12 04:51:45 +02:00
28598c9090 Merge pull request #10985 from liamwhite/handle-translate
k_server_session: translate special header for non-HLE requests
2023-07-11 16:49:24 -07:00
11cb4d88f0 Merge pull request #11070 from t895/home-setting-warning
android: Visualize disabled home options
2023-07-11 16:48:57 -07:00
4b870b28e8 android: Visualize disabled home options
Allow for displaying options in the home options that are disabled with messages that explain why they are disabled.

This includes reasoning for the GPU driver installation button.
2023-07-10 22:17:19 -04:00
ce7c418e0c Merge pull request #10996 from Kelebek1/readblock_optimisation
Use spans over guest memory where possible instead of copying data
2023-07-10 18:54:19 -07:00
169b198d08 Merge pull request #11050 from SuperSamus/sdl-button-labels
input_common: set `SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS` to 0
2023-07-10 18:53:16 -07:00
833306bf5e settings: Disable C++20 tzdb path on MinGW
This path always results in Etc/UTC on MinGW, which often is not
close to the local time zone.
2023-07-10 17:52:35 -04:00
90d76333da time_zone: Remove string ops for determing zone
MinGW's strftime implementation does not work and cannot be used to
determine the time zone. Besides that, the string operations are
actually unnecessary since we can get the offset from
std::localtime.

Compare localtime to gmtime to find the zone offset on all platforms.
2023-07-10 17:51:34 -04:00
e32ce6cc69 Merge pull request #11067 from t895/fragile-data
android: Don't prompt to save user data on uninstall
2023-07-09 17:20:14 -07:00
190748546d Merge pull request #11064 from lat9nq/mingw-no-install-pefile
ci/mingw: Remove pefile installation step
2023-07-09 19:27:52 -04:00
79e289404b Merge pull request #11055 from lat9nq/tzdb-catch-
settings: Catch runtime error from STL
2023-07-09 19:27:41 -04:00
a6e467cd55 android: Don't prompt to save user data on uninstall
While this can be convenient in some scenarios, this will be a big problem for users trying to sideload different APK versions. If they forget the last one they had installed, they could have problems installing a new copy.
2023-07-09 19:02:42 -04:00
8a87a41f2d Merge pull request #11063 from liamwhite/oops
arm_interface: correct breakpoint rewind condition
2023-07-09 16:24:49 -04:00
f02226283e ci/mingw: Remove pefile installation step
This is unnecessary here: pefile is already installed on the container.
This step also causes issues in coming changes to the container.
2023-07-09 16:07:43 -04:00
82568412f6 arm_interface: correct breakpoint rewind condition 2023-07-09 12:03:25 -04:00
1255196731 settings: Catch runtime error from STL
This function throws a runtime error we can catch on old Windows 10
installs, so we can catch it here rather than disable this path for
everybody.
2023-07-09 02:26:58 -04:00
9ce5d39829 Merge pull request #11030 from lat9nq/tz-restrict-msvc
settings: Disable C++20 time zone path on MSVC
2023-07-09 01:45:00 -04:00
4540bcfaf7 k_server_session: translate special header for non-HLE requests 2023-07-08 01:01:49 -04:00
aa882cdaa8 input_common: set SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS to 0
This allows to share the mappings between Nintendo and non-Nintendo controllers.
Breaks the controller configuration for existing users who are using a Nintendo controller.

(Documentation of the hint 92b3c53c92/include/SDL_hints.h (L512-L532))
2023-07-07 21:59:47 +02:00
b417b8562e ci/linux: Target deploy script from appimage path
Includes AppImage changes so that the needed Qt Wayland libraries are
included.
2023-07-06 20:53:22 -04:00
302a735135 settings: Disable C++20 path on MSVC
Even though it compiles and runs fine on the latest Windows versions,
older LTSC builds will crash due to lacking support somewhere in the OS.

For now just disable it for MSVC until either Microsoft fixes this or we
no longer support 1809 LTSC.
2023-07-05 15:58:12 -04:00
f1cfd9c219 Fix ScratchBuffer moves 2023-07-04 16:02:58 +01:00
6f7cb69c94 Use spans over guest memory where possible instead of copying data. 2023-07-02 23:09:48 +01:00
644c3ce609 Rename variables to avoid -Wshadow warnings under GCC 2023-07-01 22:03:21 -07:00
0ed1cb7266 ...actually add the SecureTransport backend to Git. 2023-07-01 17:48:36 -07:00
0e191c2711 Updates:
- Address PR feedback.
- Add SecureTransport backend for macOS.
2023-07-01 17:27:35 -07:00
98685d48e3 Merge remote-tracking branch 'origin/master' into ssl 2023-07-01 15:01:11 -07:00
d885dd5b64 PR feedback + constification 2023-06-25 19:24:49 -07:00
b9f9d0a642 network.cpp: include expected.h 2023-06-25 18:51:39 -07:00
8b9c077826 Disable OpenSSL on Android.
Apparently Android uses BoringSSL, but doesn't actually expose headers
for it in the NDK.
2023-06-25 17:36:51 -07:00
cd4b8f037c re-format 2023-06-25 17:09:54 -07:00
ac939f08a4 Fix more Windows build errors
I did test this beforehand, but not on MinGW, and the error that showed
up on the msvc builder didn't happen for me...
2023-06-25 17:06:57 -07:00
42015de49b ssl: fix compatibility with OpenSSL 1.1.1
Turns out changes were needed after all.
2023-06-25 16:09:16 -07:00
4a35569921 Fixes:
- Add missing virtual destructor on `SSLBackend`.

- On Windows, filter out `POLLWRBAND` (one of the new flags added) when
  calling `WSAPoll`, because despite the constant being defined on
  Windows, passing it calls `WSAPoll` to yield `EINVAL`.

- Reduce OpenSSL version requirement to satisfy CI; I haven't tested
  whether it actually builds (or runs) against 1.1.1, but if not, I'll
  figure it out.

- Change an instance of memcpy to memmove, even though the arguments
  cannot overlap, to avoid a [strange GCC
  error](https://github.com/yuzu-emu/yuzu/pull/10912#issuecomment-1606283351).
2023-06-25 15:06:52 -07:00
8905142f43 ssl: rename argument to avoid false positive codespell warning
The original name `larg` was copied from the OpenSSL documentation and
is not a typo of 'large' but rather an abbreviation of '`long`
argument'.  But whatever, no harm in adding an underscore.
2023-06-25 13:10:41 -07:00
7cc428ddf6 socket_types: Improve comment 2023-06-25 13:10:15 -07:00
8e703e08df Implement SSL service
This implements some missing network APIs including a large chunk of the SSL
service, enough for Mario Maker (with an appropriate mod applied) to connect to
the fan server [Open Course World](https://opencourse.world/).

Connecting to first-party servers is out of scope of this PR and is a
minefield I'd rather not step into.

 ## TLS

TLS is implemented with multiple backends depending on the system's 'native'
TLS library.  Currently there are two backends: Schannel for Windows, and
OpenSSL for Linux.  (In reality Linux is a bit of a free-for-all where there's
no one 'native' library, but OpenSSL is the closest it gets.)  On macOS the
'native' library is SecureTransport but that isn't implemented in this PR.
(Instead, all non-Windows OSes will use OpenSSL unless disabled with
`-DENABLE_OPENSSL=OFF`.)

Why have multiple backends instead of just using a single library, especially
given that Yuzu already embeds mbedtls for cryptographic algorithms?  Well, I
tried implementing this on mbedtls first, but the problem is TLS policies -
mainly trusted certificate policies, and to a lesser extent trusted algorithms,
SSL versions, etc.

...In practice, the chance that someone is going to conduct a man-in-the-middle
attack on a third-party game server is pretty low, but I'm a security nerd so I
like to do the right security things.

My base assumption is that we want to use the host system's TLS policies.  An
alternative would be to more closely emulate the Switch's TLS implementation
(which is based on NSS).  But for one thing, I don't feel like reverse
engineering it.  And I'd argue that for third-party servers such as Open Course
World, it's theoretically preferable to use the system's policies rather than
the Switch's, for two reasons

1. Someday the Switch will stop being updated, and the trusted cert list,
   algorithms, etc. will start to go stale, but users will still want to
   connect to third-party servers, and there's no reason they shouldn't have
   up-to-date security when doing so.  At that point, homebrew users on actual
   hardware may patch the TLS implementation, but for emulators it's simpler to
   just use the host's stack.

2. Also, it's good to respect any custom certificate policies the user may have
   added systemwide.  For example, they may have added custom trusted CAs in
   order to use TLS debugging tools or pass through corporate MitM middleboxes.
   Or they may have removed some CAs that are normally trusted out of paranoia.

Note that this policy wouldn't work as-is for connecting to first-party
servers, because some of them serve certificates based on Nintendo's own CA
rather than a publicly trusted one.  However, this could probably be solved
easily by using appropriate APIs to adding Nintendo's CA as an alternate
trusted cert for Yuzu's connections.  That is not implemented in this PR
because, again, first-party servers are out of scope.

(If anything I'd rather have an option to _block_ connections to Nintendo
servers, but that's not implemented here.)

To use the host's TLS policies, there are three theoretical options:

a) Import the host's trusted certificate list into a cross-platform TLS
   library (presumably mbedtls).

b) Use the native TLS library to verify certificates but use a cross-platform
   TLS library for everything else.

c) Use the native TLS library for everything.

Two problems with option a).  First, importing the trusted certificate list at
minimum requires a bunch of platform-specific code, which mbedtls does not have
built in.  Interestingly, OpenSSL recently gained the ability to import the
Windows certificate trust store... but that leads to the second problem, which
is that a list of trusted certificates is [not expressive
enough](https://bugs.archlinux.org/task/41909) to express a modern certificate
trust policy.  For example, Windows has the concept of [explicitly distrusted
certificates](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn265983(v=ws.11)),
and macOS requires Certificate Transparency validation for some certificates
with complex rules for when it's required.

Option b) (using native library just to verify certs) is probably feasible, but
it would miss aspects of TLS policy other than trusted certs (like allowed
algorithms), and in any case it might well require writing more code, not less,
compared to using the native library for everything.

So I ended up at option c), using the native library for everything.

What I'd *really* prefer would be to use a third-party library that does option
c) for me.  Rust has a good library for this,
[native-tls](https://docs.rs/native-tls/latest/native_tls/).  I did search, but
I couldn't find a good option in the C or C++ ecosystem, at least not any that
wasn't part of some much larger framework.  I was surprised - isn't this a
pretty common use case?  Well, many applications only need TLS for HTTPS, and they can
use libcurl, which has a TLS abstraction layer internally but doesn't expose
it.  Other applications only support a single TLS library, or use one of the
aforementioned larger frameworks, or are platform-specific to begin with, or of
course are written in a non-C/C++ language, most of which have some canonical
choice for TLS.  But there are also many applications that have a set of TLS
backends just like this; it's just that nobody has gone ahead and abstracted
the pattern into a library, at least not a widespread one.

Amusingly, there is one TLS abstraction layer that Yuzu already bundles: the
one in ffmpeg.  But it is missing some features that would be needed to use it
here (like reusing an existing socket rather than managing the socket itself).
Though, that does mean that the wiki's build instructions for Linux (and macOS
for some reason?) already recommend installing OpenSSL, so no need to update
those.

 ## Other APIs implemented

- Sockets:
    - GetSockOpt(`SO_ERROR`)
    - SetSockOpt(`SO_NOSIGPIPE`) (stub, I have no idea what this does on Switch)
    - `DuplicateSocket` (because the SSL sysmodule calls it internally)
    - More `PollEvents` values

- NSD:
    - `Resolve` and `ResolveEx` (stub, good enough for Open Course World and
      probably most third-party servers, but not first-party)

- SFDNSRES:
    - `GetHostByNameRequest` and `GetHostByNameRequestWithOptions`
    - `ResolverSetOptionRequest` (stub)

 ## Fixes

- Parts of the socket code were previously allocating a `sockaddr` object on
  the stack when calling functions that take a `sockaddr*` (e.g. `accept`).
  This might seem like the right thing to do to avoid illegal aliasing, but in
  fact `sockaddr` is not guaranteed to be large enough to hold any particular
  type of address, only the header.  This worked in practice because in
  practice `sockaddr` is the same size as `sockaddr_in`, but it's not how the
  API is meant to be used.  I changed this to allocate an `sockaddr_in` on the
  stack and `reinterpret_cast` it.  I could try to do something cleverer with
  `aligned_storage`, but casting is the idiomatic way to use these particular
  APIs, so it's really the system's responsibility to avoid any aliasing
  issues.

- I rewrote most of the `GetAddrInfoRequest[WithOptions]` implementation.  The
  old implementation invoked the host's getaddrinfo directly from sfdnsres.cpp,
  and directly passed through the host's socket type, protocol, etc. values
  rather than looking up the corresponding constants on the Switch.  To be
  fair, these constants don't tend to actually vary across systems, but
  still... I added a wrapper for `getaddrinfo` in
  `internal_network/network.cpp` similar to the ones for other socket APIs, and
  changed the `GetAddrInfoRequest` implementation to use it.  While I was at
  it, I rewrote the serialization to use the same approach I used to implement
  `GetHostByNameRequest`, because it reduces the number of size calculations.
  While doing so I removed `AF_INET6` support because the Switch doesn't
  support IPv6; it might be nice to support IPv6 anyway, but that would have to
  apply to all of the socket APIs.

  I also corrected the IPC wrappers for `GetAddrInfoRequest` and
  `GetAddrInfoRequestWithOptions` based on reverse engineering and hardware
  testing.  Every call to `GetAddrInfoRequestWithOptions` returns *four*
  different error codes (IPC status, getaddrinfo error code, netdb error code,
  and errno), and `GetAddrInfoRequest` returns three of those but in a
  different order, and it doesn't really matter but the existing implementation
  was a bit off, as I discovered while testing `GetHostByNameRequest`.

  - The new serialization code is based on two simple helper functions:

    ```cpp
    template <typename T> static void Append(std::vector<u8>& vec, T t);
    void AppendNulTerminated(std::vector<u8>& vec, std::string_view str);
    ```

    I was thinking there must be existing functions somewhere that assist with
    serialization/deserialization of binary data, but all I could find was the
    helper methods in `IOFile` and `HLERequestContext`, not anything that could
    be used with a generic byte buffer.  If I'm not missing something, then
    maybe I should move the above functions to a new header in `common`...
    right now they're just sitting in `sfdnsres.cpp` where they're used.

- Not a fix, but `SocketBase::Recv`/`Send` is changed to use `std::span<u8>`
  rather than `std::vector<u8>&` to avoid needing to copy the data to/from a
  vector when those methods are called from the TLS implementation.
2023-06-25 12:53:31 -07:00
168 changed files with 6874 additions and 3613 deletions

View File

@ -35,7 +35,7 @@ DESTDIR="$PWD/AppDir" ninja install
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
# Download tools needed to build an AppImage
wget -nc https://raw.githubusercontent.com/yuzu-emu/ext-linux-bin/main/gcc/deploy-linux.sh
wget -nc https://raw.githubusercontent.com/yuzu-emu/ext-linux-bin/main/appimage/deploy-linux.sh
wget -nc https://raw.githubusercontent.com/yuzu-emu/AppImageKit-checkrt/old/AppRun.sh
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/exec-x86_64.so
# Set executable bit

View File

@ -56,7 +56,6 @@ for i in package/*.exe; do
x86_64-w64-mingw32-strip "${i}"
done
pip3 install pefile
python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/"
# copy FFmpeg libraries

View File

@ -12,7 +12,7 @@ steps:
inputs:
targetType: 'filePath'
filePath: './.ci/scripts/windows/install-vulkan-sdk.ps1'
- script: refreshenv && glslangValidator --version && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -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} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
- script: refreshenv && glslangValidator --version && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -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} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
displayName: 'Configure CMake'
- task: MSBuild@1
displayName: 'Build'

2
.gitmodules vendored
View File

@ -56,5 +56,5 @@
path = externals/nx_tzdb/tzdb_to_nx
url = https://github.com/lat9nq/tzdb_to_nx.git
[submodule "VulkanMemoryAllocator"]
path = externals/vma/VulkanMemoryAllocator
path = externals/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git

View File

@ -63,6 +63,18 @@ option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
set(DEFAULT_ENABLE_OPENSSL ON)
if (ANDROID OR WIN32 OR APPLE)
# - Windows defaults to the Schannel backend.
# - macOS defaults to the SecureTransport backend.
# - Android currently has no SSL backend as the NDK doesn't include any SSL
# library; a proper 'native' backend would have to go through Java.
# But you can force builds for those platforms to use OpenSSL if you have
# your own copy of it.
set(DEFAULT_ENABLE_OPENSSL OFF)
endif()
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
# On Android, fetch and compile libcxx before doing anything else
if (ANDROID)
set(CMAKE_SKIP_INSTALL_RULES ON)
@ -124,6 +136,22 @@ if (YUZU_USE_BUNDLED_VCPKG)
endif()
endif()
if (MSVC)
set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads)
set(NASM_VERSION "2.16.01")
set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip)
set(NASM_DOWNLOAD_URL "https://github.com/yuzu-emu/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip")
if (NOT EXISTS ${NASM_DESTINATION_PATH})
file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS)
if (NOT NASM_STATUS EQUAL 0)
# Warn and not fail since vcpkg is supposed to download this package for us in the first place
message(WARNING "External nasm vcpkg package download from ${NASM_DOWNLOAD_URL} failed with status ${NASM_STATUS}")
endif()
endif()
endif()
if (YUZU_TESTS)
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
endif()
@ -277,10 +305,11 @@ find_package(Boost 1.79.0 REQUIRED context)
find_package(enet 1.3 MODULE)
find_package(fmt 9 REQUIRED)
find_package(inih 52 MODULE COMPONENTS INIReader)
find_package(LLVM MODULE COMPONENTS Demangle)
find_package(LLVM 17 MODULE COMPONENTS Demangle)
find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3 MODULE)
find_package(VulkanMemoryAllocator CONFIG)
find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED)
@ -322,6 +351,10 @@ if (MINGW)
find_library(MSWSOCK_LIBRARY mswsock REQUIRED)
endif()
if(ENABLE_OPENSSL)
find_package(OpenSSL 1.1.1 REQUIRED)
endif()
# Please consider this as a stub
if(ENABLE_QT6 AND Qt6_LOCATION)
list(APPEND CMAKE_PREFIX_PATH "${Qt6_LOCATION}")

View File

@ -1,3 +1,11 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -144,9 +144,9 @@ endif()
add_subdirectory(nx_tzdb)
# VMA
add_library(vma vma/vma.cpp)
target_include_directories(vma PUBLIC ./vma/VulkanMemoryAllocator/include)
target_link_libraries(vma PRIVATE Vulkan::Headers)
if (NOT TARGET GPUOpen::VulkanMemoryAllocator)
add_subdirectory(VulkanMemoryAllocator)
endif()
if (NOT TARGET LLVM::Demangle)
add_library(demangle demangle/ItaniumDemangle.cpp)

View File

@ -20,9 +20,7 @@
#include <cstdlib>
#include <cstring>
#include <functional>
#include <numeric>
#include <utility>
#include <vector>
using namespace llvm;
using namespace llvm::itanium_demangle;
@ -81,8 +79,8 @@ struct DumpVisitor {
}
void printStr(const char *S) { fprintf(stderr, "%s", S); }
void print(StringView SV) {
fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
void print(std::string_view SV) {
fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.data());
}
void print(const Node *N) {
if (N)
@ -90,14 +88,6 @@ struct DumpVisitor {
else
printStr("<null>");
}
void print(NodeOrString NS) {
if (NS.isNode())
print(NS.asNode());
else if (NS.isString())
print(NS.asString());
else
printStr("NodeOrString()");
}
void print(NodeArray A) {
++Depth;
printStr("{");
@ -116,13 +106,11 @@ struct DumpVisitor {
// Overload used when T is exactly 'bool', not merely convertible to 'bool'.
void print(bool B) { printStr(B ? "true" : "false"); }
template <class T>
typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) {
fprintf(stderr, "%llu", (unsigned long long)N);
}
template <class T>
typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) {
fprintf(stderr, "%lld", (long long)N);
}
@ -185,6 +173,50 @@ struct DumpVisitor {
return printStr("TemplateParamKind::Template");
}
}
void print(Node::Prec P) {
switch (P) {
case Node::Prec::Primary:
return printStr("Node::Prec::Primary");
case Node::Prec::Postfix:
return printStr("Node::Prec::Postfix");
case Node::Prec::Unary:
return printStr("Node::Prec::Unary");
case Node::Prec::Cast:
return printStr("Node::Prec::Cast");
case Node::Prec::PtrMem:
return printStr("Node::Prec::PtrMem");
case Node::Prec::Multiplicative:
return printStr("Node::Prec::Multiplicative");
case Node::Prec::Additive:
return printStr("Node::Prec::Additive");
case Node::Prec::Shift:
return printStr("Node::Prec::Shift");
case Node::Prec::Spaceship:
return printStr("Node::Prec::Spaceship");
case Node::Prec::Relational:
return printStr("Node::Prec::Relational");
case Node::Prec::Equality:
return printStr("Node::Prec::Equality");
case Node::Prec::And:
return printStr("Node::Prec::And");
case Node::Prec::Xor:
return printStr("Node::Prec::Xor");
case Node::Prec::Ior:
return printStr("Node::Prec::Ior");
case Node::Prec::AndIf:
return printStr("Node::Prec::AndIf");
case Node::Prec::OrIf:
return printStr("Node::Prec::OrIf");
case Node::Prec::Conditional:
return printStr("Node::Prec::Conditional");
case Node::Prec::Assign:
return printStr("Node::Prec::Assign");
case Node::Prec::Comma:
return printStr("Node::Prec::Comma");
case Node::Prec::Default:
return printStr("Node::Prec::Default");
}
}
void newLine() {
printStr("\n");
@ -334,36 +366,21 @@ public:
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
size_t *N, int *Status) {
if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
if (Status)
*Status = demangle_invalid_args;
char *llvm::itaniumDemangle(std::string_view MangledName) {
if (MangledName.empty())
return nullptr;
}
int InternalStatus = demangle_success;
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
OutputStream S;
Demangler Parser(MangledName.data(),
MangledName.data() + MangledName.length());
Node *AST = Parser.parse();
if (!AST)
return nullptr;
if (AST == nullptr)
InternalStatus = demangle_invalid_mangled_name;
else if (!initializeOutputStream(Buf, N, S, 1024))
InternalStatus = demangle_memory_alloc_failure;
else {
assert(Parser.ForwardTemplateRefs.empty());
AST->print(S);
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
Buf = S.getBuffer();
}
if (Status)
*Status = InternalStatus;
return InternalStatus == demangle_success ? Buf : nullptr;
OutputBuffer OB;
assert(Parser.ForwardTemplateRefs.empty());
AST->print(OB);
OB += '\0';
return OB.getBuffer();
}
ItaniumPartialDemangler::ItaniumPartialDemangler()
@ -396,14 +413,12 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
}
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
RootNode->print(S);
S += '\0';
OutputBuffer OB(Buf, N);
RootNode->print(OB);
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
@ -417,8 +432,8 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
case Node::KAbiTagAttr:
Name = static_cast<const AbiTagAttr *>(Name)->Base;
continue;
case Node::KStdQualifiedName:
Name = static_cast<const StdQualifiedName *>(Name)->Child;
case Node::KModuleEntity:
Name = static_cast<const ModuleEntity *>(Name)->Name;
continue;
case Node::KNestedName:
Name = static_cast<const NestedName *>(Name)->Name;
@ -441,9 +456,7 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
return nullptr;
const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
OutputBuffer OB(Buf, N);
KeepGoingLocalFunction:
while (true) {
@ -458,27 +471,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
break;
}
if (Name->getKind() == Node::KModuleEntity)
Name = static_cast<const ModuleEntity *>(Name)->Name;
switch (Name->getKind()) {
case Node::KStdQualifiedName:
S += "std";
break;
case Node::KNestedName:
static_cast<const NestedName *>(Name)->Qual->print(S);
static_cast<const NestedName *>(Name)->Qual->print(OB);
break;
case Node::KLocalName: {
auto *LN = static_cast<const LocalName *>(Name);
LN->Encoding->print(S);
S += "::";
LN->Encoding->print(OB);
OB += "::";
Name = LN->Entity;
goto KeepGoingLocalFunction;
}
default:
break;
}
S += '\0';
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
@ -494,17 +507,15 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
return nullptr;
NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
OutputBuffer OB(Buf, N);
S += '(';
Params.printWithComma(S);
S += ')';
S += '\0';
OB += '(';
Params.printWithComma(OB);
OB += ')';
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionReturnType(
@ -512,18 +523,16 @@ char *ItaniumPartialDemangler::getFunctionReturnType(
if (!isFunction())
return nullptr;
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
OutputBuffer OB(Buf, N);
if (const Node *Ret =
static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
Ret->print(S);
Ret->print(OB);
S += '\0';
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
@ -563,8 +572,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
case Node::KNestedName:
N = static_cast<const NestedName *>(N)->Name;
break;
case Node::KStdQualifiedName:
N = static_cast<const StdQualifiedName *>(N)->Child;
case Node::KModuleEntity:
N = static_cast<const ModuleEntity *>(N)->Name;
break;
}
}

View File

@ -12,6 +12,7 @@
#include <cstddef>
#include <string>
#include <string_view>
namespace llvm {
/// This is a llvm local version of __cxa_demangle. Other than the name and
@ -29,9 +30,10 @@ enum : int {
demangle_success = 0,
};
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
int *status);
/// Returns a non-NULL pointer to a NUL-terminated C style string
/// that should be explicitly freed, if successful. Otherwise, may return
/// nullptr if mangled_name is not a valid mangling or is nullptr.
char *itaniumDemangle(std::string_view mangled_name);
enum MSDemangleFlags {
MSDF_None = 0,
@ -40,10 +42,34 @@ enum MSDemangleFlags {
MSDF_NoCallingConvention = 1 << 2,
MSDF_NoReturnType = 1 << 3,
MSDF_NoMemberType = 1 << 4,
MSDF_NoVariableType = 1 << 5,
};
char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
/// Returns a pointer to the start of a null-terminated demangled string on
/// success, or nullptr on error.
/// If n_read is non-null and demangling was successful, it receives how many
/// bytes of the input string were consumed.
/// status receives one of the demangle_ enum entries above if it's not nullptr.
/// Flags controls various details of the demangled representation.
char *microsoftDemangle(std::string_view mangled_name, size_t *n_read,
int *status, MSDemangleFlags Flags = MSDF_None);
// Demangles a Rust v0 mangled symbol.
char *rustDemangle(std::string_view MangledName);
// Demangles a D mangled symbol.
char *dlangDemangle(std::string_view MangledName);
/// Attempt to demangle a string using different demangling schemes.
/// The function uses heuristics to determine which demangling scheme to use.
/// \param MangledName - reference to string to demangle.
/// \returns - the demangled string, or a copy of the input string if no
/// demangling occurred.
std::string demangle(std::string_view MangledName);
bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result);
/// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain
/// properties or partially printing the demangled name.
@ -59,7 +85,7 @@ struct ItaniumPartialDemangler {
bool partialDemangle(const char *MangledName);
/// Just print the entire mangled name into Buf. Buf and N behave like the
/// second and third parameters to itaniumDemangle.
/// second and third parameters to __cxa_demangle.
char *finishDemangle(char *Buf, size_t *N) const;
/// Get the base name of a function. This doesn't include trailing template
@ -95,6 +121,7 @@ struct ItaniumPartialDemangler {
bool isSpecialName() const;
~ItaniumPartialDemangler();
private:
void *RootNode;
void *Context;

View File

@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_COMPILER_H
#define LLVM_DEMANGLE_COMPILER_H
#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H
#define LLVM_DEMANGLE_DEMANGLECONFIG_H
#ifndef __has_feature
#define __has_feature(x) 0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Define the demangler's node names
#ifndef NODE
#error Define NODE to handle nodes
#endif
NODE(NodeArrayNode)
NODE(DotSuffix)
NODE(VendorExtQualType)
NODE(QualType)
NODE(ConversionOperatorType)
NODE(PostfixQualifiedType)
NODE(ElaboratedTypeSpefType)
NODE(NameType)
NODE(AbiTagAttr)
NODE(EnableIfAttr)
NODE(ObjCProtoName)
NODE(PointerType)
NODE(ReferenceType)
NODE(PointerToMemberType)
NODE(ArrayType)
NODE(FunctionType)
NODE(NoexceptSpec)
NODE(DynamicExceptionSpec)
NODE(FunctionEncoding)
NODE(LiteralOperator)
NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
NODE(VectorType)
NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
NODE(TypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
NODE(ParameterPack)
NODE(TemplateArgumentPack)
NODE(ParameterPackExpansion)
NODE(TemplateArgs)
NODE(ForwardTemplateReference)
NODE(NameWithTemplateArgs)
NODE(GlobalQualifiedName)
NODE(ExpandedSpecialSubstitution)
NODE(SpecialSubstitution)
NODE(CtorDtorName)
NODE(DtorName)
NODE(UnnamedTypeName)
NODE(ClosureTypeName)
NODE(StructuredBindingName)
NODE(BinaryExpr)
NODE(ArraySubscriptExpr)
NODE(PostfixExpr)
NODE(ConditionalExpr)
NODE(MemberExpr)
NODE(SubobjectExpr)
NODE(EnclosingExpr)
NODE(CastExpr)
NODE(SizeofParamPackExpr)
NODE(CallExpr)
NODE(NewExpr)
NODE(DeleteExpr)
NODE(PrefixExpr)
NODE(FunctionParam)
NODE(ConversionExpr)
NODE(PointerToMemberConversionExpr)
NODE(InitListExpr)
NODE(FoldExpr)
NODE(ThrowExpr)
NODE(BoolExpr)
NODE(StringLiteral)
NODE(LambdaExpr)
NODE(EnumLiteral)
NODE(IntegerLiteral)
NODE(FloatLiteral)
NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
#undef NODE

View File

@ -1,5 +1,5 @@
//===--- StringView.h -------------------------------------------*- C++ -*-===//
//
//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
@ -8,6 +8,9 @@
//===----------------------------------------------------------------------===//
//
// FIXME: Use std::string_view instead when we support C++17.
// There are two copies of this file in the source tree. The one under
// libcxxabi is the original and the one under llvm is the copy. Use
// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
@ -15,7 +18,6 @@
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <algorithm>
#include <cassert>
#include <cstring>
@ -37,29 +39,23 @@ public:
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView() : First(nullptr), Last(nullptr) {}
StringView substr(size_t From) const {
return StringView(begin() + From, size() - From);
StringView substr(size_t Pos, size_t Len = npos) const {
assert(Pos <= size());
if (Len > size() - Pos)
Len = size() - Pos;
return StringView(begin() + Pos, Len);
}
size_t find(char C, size_t From = 0) const {
size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr.
if (FindBegin < size()) {
if (From < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
if (const void *P = ::memchr(First + From, C, size() - From))
return size_t(static_cast<const char *>(P) - First);
}
return npos;
}
StringView substr(size_t From, size_t To) const {
if (To >= size())
To = size() - 1;
if (From >= size())
From = size() - 1;
return StringView(First + From, First + To);
}
StringView dropFront(size_t N = 1) const {
if (N >= size())
N = size();
@ -106,7 +102,7 @@ public:
bool startsWith(StringView Str) const {
if (Str.size() > size())
return false;
return std::equal(Str.begin(), Str.end(), begin());
return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
}
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
@ -119,7 +115,7 @@ public:
inline bool operator==(const StringView &LHS, const StringView &RHS) {
return LHS.size() == RHS.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
}
DEMANGLE_NAMESPACE_END

View File

@ -0,0 +1,39 @@
//===--- StringViewExtras.h ----------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// There are two copies of this file in the source tree. The one under
// libcxxabi is the original and the one under llvm is the copy. Use
// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <string_view>
DEMANGLE_NAMESPACE_BEGIN
inline bool starts_with(std::string_view self, char C) noexcept {
return !self.empty() && *self.begin() == C;
}
inline bool starts_with(std::string_view haystack,
std::string_view needle) noexcept {
if (needle.size() > haystack.size())
return false;
haystack.remove_suffix(haystack.size() - needle.size());
return haystack == needle;
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -1,5 +1,5 @@
//===--- Utility.h ----------------------------------------------*- C++ -*-===//
//
//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
@ -7,70 +7,83 @@
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler(s).
// Provide some utility classes for use in the demangler.
// There are two copies of this file in the source tree. The one in libcxxabi
// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
// the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
#include "StringView.h"
#include "DemangleConfig.h"
#include <array>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <exception>
#include <limits>
#include <string_view>
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputStream {
char *Buffer;
size_t CurrentPosition;
size_t BufferCapacity;
class OutputBuffer {
char *Buffer = nullptr;
size_t CurrentPosition = 0;
size_t BufferCapacity = 0;
// Ensure there is at least n more positions in buffer.
// Ensure there are at least N more positions in the buffer.
void grow(size_t N) {
if (N + CurrentPosition >= BufferCapacity) {
size_t Need = N + CurrentPosition;
if (Need > BufferCapacity) {
// Reduce the number of reallocations, with a bit of hysteresis. The
// number here is chosen so the first allocation will more-than-likely not
// allocate more than 1K.
Need += 1024 - 32;
BufferCapacity *= 2;
if (BufferCapacity < N + CurrentPosition)
BufferCapacity = N + CurrentPosition;
if (BufferCapacity < Need)
BufferCapacity = Need;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
void writeUnsigned(uint64_t N, bool isNeg = false) {
// Handle special case...
if (N == 0) {
*this << '0';
return;
}
OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
std::array<char, 21> Temp;
char *TempPtr = Temp.data() + Temp.size();
char Temp[21];
char *TempPtr = std::end(Temp);
while (N) {
*--TempPtr = '0' + char(N % 10);
// Output at least one character.
do {
*--TempPtr = char('0' + N % 10);
N /= 10;
}
} while (N);
// Add negative sign...
// Add negative sign.
if (isNeg)
*--TempPtr = '-';
this->operator<<(StringView(TempPtr, std::end(Temp)));
return operator+=(
std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
}
public:
OutputStream(char *StartBuf, size_t Size)
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
OutputStream() = default;
void reset(char *Buffer_, size_t BufferCapacity_) {
CurrentPosition = 0;
Buffer = Buffer_;
BufferCapacity = BufferCapacity_;
OutputBuffer(char *StartBuf, size_t Size)
: Buffer(StartBuf), BufferCapacity(Size) {}
OutputBuffer(char *StartBuf, size_t *SizePtr)
: OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
OutputBuffer() = default;
// Non-copyable
OutputBuffer(const OutputBuffer &) = delete;
OutputBuffer &operator=(const OutputBuffer &) = delete;
operator std::string_view() const {
return std::string_view(Buffer, CurrentPosition);
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
@ -78,115 +91,116 @@ public:
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
OutputStream &operator+=(StringView R) {
size_t Size = R.size();
if (Size == 0)
return *this;
grow(Size);
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
CurrentPosition += Size;
/// When zero, we're printing template args and '>' needs to be parenthesized.
/// Use a counter so we can simply increment inside parentheses.
unsigned GtIsGt = 1;
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
void printOpen(char Open = '(') {
GtIsGt++;
*this += Open;
}
void printClose(char Close = ')') {
GtIsGt--;
*this += Close;
}
OutputBuffer &operator+=(std::string_view R) {
if (size_t Size = R.size()) {
grow(Size);
std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);
CurrentPosition += Size;
}
return *this;
}
OutputStream &operator+=(char C) {
OutputBuffer &operator+=(char C) {
grow(1);
Buffer[CurrentPosition++] = C;
return *this;
}
OutputStream &operator<<(StringView R) { return (*this += R); }
OutputBuffer &prepend(std::string_view R) {
size_t Size = R.size();
OutputStream &operator<<(char C) { return (*this += C); }
grow(Size);
std::memmove(Buffer + Size, Buffer, CurrentPosition);
std::memcpy(Buffer, &*R.begin(), Size);
CurrentPosition += Size;
OutputStream &operator<<(long long N) {
if (N < 0)
writeUnsigned(static_cast<unsigned long long>(-N), true);
else
writeUnsigned(static_cast<unsigned long long>(N));
return *this;
}
OutputStream &operator<<(unsigned long long N) {
writeUnsigned(N, false);
return *this;
OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
OutputBuffer &operator<<(char C) { return (*this += C); }
OutputBuffer &operator<<(long long N) {
return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
}
OutputStream &operator<<(long N) {
OutputBuffer &operator<<(unsigned long long N) {
return writeUnsigned(N, false);
}
OutputBuffer &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned long N) {
OutputBuffer &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
OutputStream &operator<<(int N) {
OutputBuffer &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned int N) {
OutputBuffer &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
void insert(size_t Pos, const char *S, size_t N) {
assert(Pos <= CurrentPosition);
if (N == 0)
return;
grow(N);
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
std::memcpy(Buffer + Pos, S, N);
CurrentPosition += N;
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
assert(CurrentPosition);
return Buffer[CurrentPosition - 1];
}
bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() { return BufferCapacity; }
size_t getBufferCapacity() const { return BufferCapacity; }
};
template <class T> class SwapAndRestore {
T &Restore;
T OriginalValue;
bool ShouldRestore = true;
template <class T> class ScopedOverride {
T &Loc;
T Original;
public:
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
SwapAndRestore(T &Restore_, T NewVal)
: Restore(Restore_), OriginalValue(Restore) {
Restore = std::move(NewVal);
}
~SwapAndRestore() {
if (ShouldRestore)
Restore = std::move(OriginalValue);
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
Loc_ = std::move(NewVal);
}
~ScopedOverride() { Loc = std::move(Original); }
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
void restoreNow(bool Force) {
if (!Force && !ShouldRestore)
return;
Restore = std::move(OriginalValue);
ShouldRestore = false;
}
SwapAndRestore(const SwapAndRestore &) = delete;
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
ScopedOverride(const ScopedOverride &) = delete;
ScopedOverride &operator=(const ScopedOverride &) = delete;
};
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
size_t InitSize) {
size_t BufferSize;
if (Buf == nullptr) {
Buf = static_cast<char *>(std::malloc(InitSize));
if (Buf == nullptr)
return false;
BufferSize = InitSize;
} else
BufferSize = *N;
S.reset(Buf, BufferSize);
return true;
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -22,7 +22,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:label="@string/app_name_suffixed"
android:icon="@drawable/ic_launcher"
android:allowBackup="true"
android:hasFragileUserData="true"
android:hasFragileUserData="false"
android:supportsRtl="true"
android:isGame="true"
android:localeConfig="@xml/locales_config"

View File

@ -12,6 +12,7 @@ import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.HomeSetting
class HomeSettingAdapter(private val activity: AppCompatActivity, var options: List<HomeSetting>) :
@ -34,7 +35,14 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
override fun onClick(view: View) {
val holder = view.tag as HomeOptionViewHolder
holder.option.onClick.invoke()
if (holder.option.isEnabled.invoke()) {
holder.option.onClick.invoke()
} else {
MessageDialogFragment.newInstance(
holder.option.disabledTitleId,
holder.option.disabledMessageId
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
}
}
inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
@ -65,6 +73,12 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
R.drawable.premium_background
)
}
if (!option.isEnabled.invoke()) {
binding.optionTitle.alpha = 0.5f
binding.optionDescription.alpha = 0.5f
binding.optionIcon.alpha = 0.5f
}
}
}
}

View File

@ -73,102 +73,113 @@ class HomeSettingsFragment : Fragment() {
HomeSetting(
R.string.advanced_settings,
R.string.settings_description,
R.drawable.ic_settings
) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
R.drawable.ic_settings,
{ SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
)
)
add(
HomeSetting(
R.string.open_user_folder,
R.string.open_user_folder_description,
R.drawable.ic_folder_open
) { openFileManager() }
R.drawable.ic_folder_open,
{ openFileManager() }
)
)
add(
HomeSetting(
R.string.preferences_theme,
R.string.theme_and_color_description,
R.drawable.ic_palette
) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
)
if (GpuDriverHelper.supportsCustomDriverLoading()) {
add(
HomeSetting(
R.string.install_gpu_driver,
R.string.install_gpu_driver_description,
R.drawable.ic_exit
) { driverInstaller() }
R.drawable.ic_palette,
{ SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
)
}
)
add(
HomeSetting(
R.string.install_gpu_driver,
R.string.install_gpu_driver_description,
R.drawable.ic_exit,
{ driverInstaller() },
{ GpuDriverHelper.supportsCustomDriverLoading() },
R.string.custom_driver_not_supported,
R.string.custom_driver_not_supported_description
)
)
add(
HomeSetting(
R.string.install_amiibo_keys,
R.string.install_amiibo_keys_description,
R.drawable.ic_nfc
) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
R.drawable.ic_nfc,
{ mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
)
)
add(
HomeSetting(
R.string.install_game_content,
R.string.install_game_content_description,
R.drawable.ic_system_update_alt
) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
R.drawable.ic_system_update_alt,
{ mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
)
)
add(
HomeSetting(
R.string.select_games_folder,
R.string.select_games_folder_description,
R.drawable.ic_add
) {
mainActivity.getGamesDirectory.launch(
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
)
}
R.drawable.ic_add,
{
mainActivity.getGamesDirectory.launch(
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
)
}
)
)
add(
HomeSetting(
R.string.manage_save_data,
R.string.import_export_saves_description,
R.drawable.ic_save
) {
ImportExportSavesFragment().show(
parentFragmentManager,
ImportExportSavesFragment.TAG
)
}
R.drawable.ic_save,
{
ImportExportSavesFragment().show(
parentFragmentManager,
ImportExportSavesFragment.TAG
)
}
)
)
add(
HomeSetting(
R.string.install_prod_keys,
R.string.install_prod_keys_description,
R.drawable.ic_unlock
) { mainActivity.getProdKey.launch(arrayOf("*/*")) }
R.drawable.ic_unlock,
{ mainActivity.getProdKey.launch(arrayOf("*/*")) }
)
)
add(
HomeSetting(
R.string.install_firmware,
R.string.install_firmware_description,
R.drawable.ic_firmware
) { mainActivity.getFirmware.launch(arrayOf("application/zip")) }
R.drawable.ic_firmware,
{ mainActivity.getFirmware.launch(arrayOf("application/zip")) }
)
)
add(
HomeSetting(
R.string.share_log,
R.string.share_log_description,
R.drawable.ic_log
) { shareLog() }
R.drawable.ic_log,
{ shareLog() }
)
)
add(
HomeSetting(
R.string.about,
R.string.about_description,
R.drawable.ic_info_outline
) {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
parentFragmentManager.primaryNavigationFragment?.findNavController()
?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
}
R.drawable.ic_info_outline,
{
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
parentFragmentManager.primaryNavigationFragment?.findNavController()
?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
}
)
)
}
@ -178,12 +189,13 @@ class HomeSettingsFragment : Fragment() {
HomeSetting(
R.string.get_early_access,
R.string.get_early_access_description,
R.drawable.ic_diamond
) {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
parentFragmentManager.primaryNavigationFragment?.findNavController()
?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment)
}
R.drawable.ic_diamond,
{
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
parentFragmentManager.primaryNavigationFragment?.findNavController()
?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment)
}
)
)
}

View File

@ -7,5 +7,8 @@ data class HomeSetting(
val titleId: Int,
val descriptionId: Int,
val iconId: Int,
val onClick: () -> Unit
val onClick: () -> Unit,
val isEnabled: () -> Boolean = { true },
val disabledTitleId: Int = 0,
val disabledMessageId: Int = 0
)

View File

@ -449,7 +449,7 @@ private:
loader->ReadTitle(entry.title);
loader->ReadIcon(entry.icon);
if (loader->GetFileType() == Loader::FileType::NRO) {
jauto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
jauto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;

View File

@ -235,26 +235,6 @@
<string name="region_korea">Korea</string>
<string name="region_taiwan">Taiwan</string>
<!-- Language Names -->
<string name="language_japanese">Japanisch (日本語)</string>
<string name="language_english">Englisch</string>
<string name="language_french">Französisch (Français)</string>
<string name="langauge_german">Deutsch (German)</string>
<string name="language_italian">Italienisch (Italiano)</string>
<string name="language_spanish">Spanisch (Español)</string>
<string name="language_chinese">Chinesisch (简体中文)</string>
<string name="language_korean">Koreanisch (한국어)</string>
<string name="language_dutch">Niederländisch (Nederlands)</string>
<string name="language_portuguese">Portugiesisch (Português)</string>
<string name="language_russian">Russisch (Русский)</string>
<string name="language_taiwanese">Taiwanesisch (台湾)</string>
<string name="language_british_english">Britisches Englisch</string>
<string name="language_canadian_french">Kanadisches Französisch (Français canadien)</string>
<string name="language_latin_american_spanish">Lateinamerikanisches Spanisch (Español latinoamericano)</string>
<string name="language_simplified_chinese">Vereinfachtes Chinesisch (简体中文)</string>
<string name="language_traditional_chinese">Traditionelles Chinesisch (正體中文)</string>
<string name="language_brazilian_portuguese">Brasilianisches Portugiesisch (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>
<string name="renderer_none">Keiner</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Taiwán</string>
<!-- Language Names -->
<string name="language_japanese">Japonés (日本語)</string>
<string name="language_english">Inglés (English)</string>
<string name="language_french">Francés (Français)</string>
<string name="langauge_german">Alemán (deutsch)</string>
<string name="language_italian">Italiano (Italiano)</string>
<string name="language_spanish">Español (Español)</string>
<string name="language_chinese">Chino (简体中文)</string>
<string name="language_korean">Coreano (한국어)</string>
<string name="language_dutch">Holandés (nederlands)</string>
<string name="language_portuguese">Portugués (Português)</string>
<string name="language_russian">Ruso (Русский)</string>
<string name="language_taiwanese">Taiwanés (台湾)</string>
<string name="language_british_english">Inglés británico</string>
<string name="language_canadian_french">Francés Canadiense (Français canadien)</string>
<string name="language_latin_american_spanish">Español Latinoamericano (Español latinoamericano)</string>
<string name="language_simplified_chinese">Chino Simplificado (简体中文)</string>
<string name="language_traditional_chinese">Chino tradicional (正體中文)</string>
<string name="language_brazilian_portuguese">Portugués Brasileño (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Taïwan</string>
<!-- Language Names -->
<string name="language_japanese">Japonais (日本語)</string>
<string name="language_english">Anglais</string>
<string name="language_french">Français (Français)</string>
<string name="langauge_german">Allemand (Deutsch)</string>
<string name="language_italian">Italien (Italiano)</string>
<string name="language_spanish">Espagnol (Español)</string>
<string name="language_chinese">Chinois (简体中文)</string>
<string name="language_korean">Coréen (한국어)</string>
<string name="language_dutch">Néerlandais (Nederlands)</string>
<string name="language_portuguese">Portugais (Português)</string>
<string name="language_russian">Russe (Русский)</string>
<string name="language_taiwanese">Taïwanais (台湾)</string>
<string name="language_british_english">Anglais Britannique</string>
<string name="language_canadian_french">Français canadien (Français canadien)</string>
<string name="language_latin_american_spanish">Espagnol latino-américain (Español latinoamericano)</string>
<string name="language_simplified_chinese">Chinois simplifié (简体中文)</string>
<string name="language_traditional_chinese">Chinois Traditionnel (正體中文)</string>
<string name="language_brazilian_portuguese">Portugais brésilien (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Taiwan</string>
<!-- Language Names -->
<string name="language_japanese">Giapponese (日本語)</string>
<string name="language_english">Inglese (English)</string>
<string name="language_french">Francese (Français)</string>
<string name="langauge_german">Tedesco (Deutsch)</string>
<string name="language_italian">Italiano (Italiano)</string>
<string name="language_spanish">Spagnolo (Español)</string>
<string name="language_chinese">Cinese (简体中文)</string>
<string name="language_korean">Coreano (한국어)</string>
<string name="language_dutch">Olandese (Nederlands)</string>
<string name="language_portuguese">Portoghese (Português)</string>
<string name="language_russian">Russo (Русский)</string>
<string name="language_taiwanese">Taiwanese (台湾)</string>
<string name="language_british_english">Inglese britannico</string>
<string name="language_canadian_french">Francese Canadese (Français canadien)</string>
<string name="language_latin_american_spanish">Spagnolo Latino Americano (Español latinoamericano)</string>
<string name="language_simplified_chinese">Cinese Semplificato (简体中文)</string>
<string name="language_traditional_chinese">Cinese tradizionale (正體中文)</string>
<string name="language_brazilian_portuguese">Portoghese (Português)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -239,24 +239,6 @@
<string name="region_taiwan">台湾</string>
<!-- Language Names -->
<string name="language_japanese">日本語</string>
<string name="language_english">英語</string>
<string name="language_french">フランス語 (Français)</string>
<string name="langauge_german">ドイツ語 (Deutsch)</string>
<string name="language_italian">イタリア語 (Italiano)</string>
<string name="language_spanish">スペイン語 (Español)</string>
<string name="language_chinese">中国語 (简体中文)</string>
<string name="language_korean">韓国語 (한국어)</string>
<string name="language_dutch">オランダ語 (Nederlands)</string>
<string name="language_portuguese">ポルトガル語 (Português)</string>
<string name="language_russian">ロシア語 (Русский)</string>
<string name="language_taiwanese">台湾語 (台湾)</string>
<string name="language_british_english">イギリス英語</string>
<string name="language_canadian_french">フランス語(カナダ) (Français canadien)</string>
<string name="language_latin_american_spanish">スペイン語(ラテンアメリカ) (Español latinoamericano)</string>
<string name="language_simplified_chinese">中国語 (简体中文)</string>
<string name="language_traditional_chinese">繁体字中国語 (正體中文)</string>
<string name="language_brazilian_portuguese">ポルトガル語(ブラジル) (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">타이완</string>
<!-- Language Names -->
<string name="language_japanese">일본어 (日本語)</string>
<string name="language_english">영어 (English)</string>
<string name="language_french">프랑스어 (Français)</string>
<string name="langauge_german">독일어(Deutsch)</string>
<string name="language_italian">이탈리아어 (Italiano)</string>
<string name="language_spanish">스페인어 (Español)</string>
<string name="language_chinese">중국어 (简体中文)</string>
<string name="language_korean">한국어 (Korean)</string>
<string name="language_dutch">네덜란드어 (Nederlands)</string>
<string name="language_portuguese">포르투갈어 (Português)</string>
<string name="language_russian">러시아어 (Русский)</string>
<string name="language_taiwanese">대만어 (台湾)</string>
<string name="language_british_english">영어 (British English)</string>
<string name="language_canadian_french">캐나다 프랑스어 (Français canadien)</string>
<string name="language_latin_american_spanish">라틴 아메리카 스페인어 (Español latinoamericano)</string>
<string name="language_simplified_chinese">중국어 간체 (简体中文)</string>
<string name="language_traditional_chinese">중국어 번체 (正體中文)</string>
<string name="language_brazilian_portuguese">브라질 포르투갈어 (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">불칸</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Taiwan</string>
<!-- Language Names -->
<string name="language_japanese">Japansk (日本語)</string>
<string name="language_english">Engelsk</string>
<string name="language_french">Fransk (Français)</string>
<string name="langauge_german">Tysk (Deutsch)</string>
<string name="language_italian">Italiensk (Italiano)</string>
<string name="language_spanish">Spansk (Español)</string>
<string name="language_chinese">Kinesisk (简体中文)</string>
<string name="language_korean">Koreansk (한국어)</string>
<string name="language_dutch">Nederlandsk (Nederlands)</string>
<string name="language_portuguese">Portugisisk (Português)</string>
<string name="language_russian">Russisk (Русский)</string>
<string name="language_taiwanese">Taiwansk (台湾)</string>
<string name="language_british_english">Britisk Engelsk</string>
<string name="language_canadian_french">Kanadisk fransk (Français canadien)</string>
<string name="language_latin_american_spanish">Latinamerikansk spansk (Español latinoamericano)</string>
<string name="language_simplified_chinese">Forenklet kinesisk (简体中文)</string>
<string name="language_traditional_chinese">Tradisjonell Kinesisk (正體中文)</string>
<string name="language_brazilian_portuguese">Brasiliansk portugisisk (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Tajwan</string>
<!-- Language Names -->
<string name="language_japanese">Japoński (日本語)</string>
<string name="language_english">Angielski</string>
<string name="language_french">Francuski (Francja)</string>
<string name="langauge_german">Niemiecki (Niemcy)</string>
<string name="language_italian">Włoski (Włochy)</string>
<string name="language_spanish">Hiszpański (Hiszpania)</string>
<string name="language_chinese">Chiński (简体中文)</string>
<string name="language_korean">Koreański (한국어)</string>
<string name="language_dutch">Duński (Holandia)</string>
<string name="language_portuguese">Portugalski (Portugalia)</string>
<string name="language_russian">Rosyjski (Русский)</string>
<string name="language_taiwanese">Tajwański (台湾)</string>
<string name="language_british_english">Angielski Brytyjski</string>
<string name="language_canadian_french">Francuski (Kanada)</string>
<string name="language_latin_american_spanish">Hiszpański (Ameryka Latynoska)</string>
<string name="language_simplified_chinese">Chiński uproszczony (简体中文)</string>
<string name="language_traditional_chinese">Chiński tradycyjny (正體中文)</string>
<string name="language_brazilian_portuguese">Portugalski (Brazylia)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Taiwan</string>
<!-- Language Names -->
<string name="language_japanese">Japônes (日本語)</string>
<string name="language_english">Português do Brasil</string>
<string name="language_french">Francês (Français)</string>
<string name="langauge_german">Alemão (Deutsch)</string>
<string name="language_italian">Italiano (Italiano)</string>
<string name="language_spanish">Espanhol (Español)</string>
<string name="language_chinese">Mandarim (简体中文)</string>
<string name="language_korean">Coreano (한국어)</string>
<string name="language_dutch">Holandês (Nederlands)</string>
<string name="language_portuguese">Português (Português)</string>
<string name="language_russian">Russo (Русский)</string>
<string name="language_taiwanese">Taiwanês (台湾)</string>
<string name="language_british_english">Inglês britânico (British English)</string>
<string name="language_canadian_french">Fracês Canadiano (Français canadien)</string>
<string name="language_latin_american_spanish">Espanhol da América Latina (Español latino-americano)</string>
<string name="language_simplified_chinese">Chinês Simplificado (简体中文)</string>
<string name="language_traditional_chinese">Chinês tradicional (正體中文)</string>
<string name="language_brazilian_portuguese">Português do Brasil (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulcano</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Taiwan</string>
<!-- Language Names -->
<string name="language_japanese">Japonês (日本語)</string>
<string name="language_english">Inglês</string>
<string name="language_french">Francês (Français)</string>
<string name="langauge_german">Alemão (Deutsch)</string>
<string name="language_italian">Italiano (Italiano)</string>
<string name="language_spanish">Espanhol (Español)</string>
<string name="language_chinese">Chinês simplificado (简体中文)</string>
<string name="language_korean">Coreano (한국어)</string>
<string name="language_dutch">Holandês (Nederlands)</string>
<string name="language_portuguese">Português (Português)</string>
<string name="language_russian">Russo (Русский)</string>
<string name="language_taiwanese">Taiwanês (台湾)</string>
<string name="language_british_english">Inglês Britânico</string>
<string name="language_canadian_french">Fracês Canadiano (Français canadien)</string>
<string name="language_latin_american_spanish">Espanhol da América Latina (Español latino-americano)</string>
<string name="language_simplified_chinese">Chinês Simplificado (简体中文)</string>
<string name="language_traditional_chinese">Chinês Tradicional (正 體 中文)</string>
<string name="language_brazilian_portuguese">Português do Brasil (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulcano</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Тайвань</string>
<!-- Language Names -->
<string name="language_japanese">Японский (日本語)</string>
<string name="language_english">Английский (English)</string>
<string name="language_french">Французский (Français)</string>
<string name="langauge_german">Немецкий (Deutsch)</string>
<string name="language_italian">Итальянский (Italiano)</string>
<string name="language_spanish">Испанский (Español)</string>
<string name="language_chinese">Китайский (简体中文)</string>
<string name="language_korean">Корейский (한국어)</string>
<string name="language_dutch">Голландский (Nederlands)</string>
<string name="language_portuguese">Португальский (Português)</string>
<string name="language_russian">Русский</string>
<string name="language_taiwanese">Тайваньский (台湾)</string>
<string name="language_british_english">Британский английский</string>
<string name="language_canadian_french">Канадский французский (Français canadien)</string>
<string name="language_latin_american_spanish">Латиноамериканский испанский (Español latinoamericano)</string>
<string name="language_simplified_chinese">Упрощенный китайский (简体中文)</string>
<string name="language_traditional_chinese">Традиционный китайский (正體中文)</string>
<string name="language_brazilian_portuguese">Бразильский португальский (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">Тайвань</string>
<!-- Language Names -->
<string name="language_japanese">Японська (日本語)</string>
<string name="language_english">Англійська (English)</string>
<string name="language_french">Французька (Français)</string>
<string name="langauge_german">Німецька (Deutsch)</string>
<string name="language_italian">Італійська (Italiano)</string>
<string name="language_spanish">Іспанська (Español)</string>
<string name="language_chinese">Китайскька (简体中文)</string>
<string name="language_korean">Корейська (한국어)</string>
<string name="language_dutch">Голландська (Nederlands)</string>
<string name="language_portuguese">Португальська (Português)</string>
<string name="language_russian">Російська (Русский)</string>
<string name="language_taiwanese">Тайванська (台湾)</string>
<string name="language_british_english">Британська англійська</string>
<string name="language_canadian_french">Канадська французька (Français canadien)</string>
<string name="language_latin_american_spanish">Латиноамериканська іспанська (Español latinoamericano)</string>
<string name="language_simplified_chinese">Спрощена китайська (简体中文)</string>
<string name="language_traditional_chinese">Традиційна китайська (正體中文)</string>
<string name="language_brazilian_portuguese">Бразильська португальська (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">中国台湾</string>
<!-- Language Names -->
<string name="language_japanese">日语 (日本語)</string>
<string name="language_english">英语 (English)</string>
<string name="language_french">法语 (Français)</string>
<string name="langauge_german">德语 (Deutsch)</string>
<string name="language_italian">意大利语 (Italiano)</string>
<string name="language_spanish">西班牙语 (Español)</string>
<string name="language_chinese">中文 (简体中文)</string>
<string name="language_korean">韩语 (한국어)</string>
<string name="language_dutch">荷兰语 (Nederlands)</string>
<string name="language_portuguese">葡萄牙语 (Português)</string>
<string name="language_russian">俄语 (Русский)</string>
<string name="language_taiwanese">台湾中文 (台灣)</string>
<string name="language_british_english">英式英语</string>
<string name="language_canadian_french">加拿大法语 (Français canadien)</string>
<string name="language_latin_american_spanish">拉丁美洲西班牙语 (Español latinoamericano)</string>
<string name="language_simplified_chinese">简体中文 (简体中文)</string>
<string name="language_traditional_chinese">繁体中文 (正體中文)</string>
<string name="language_brazilian_portuguese">巴西葡萄牙语 (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -241,24 +241,6 @@
<string name="region_taiwan">台灣</string>
<!-- Language Names -->
<string name="language_japanese">日文 (日本語)</string>
<string name="language_english">英文</string>
<string name="language_french">法文 (Français)</string>
<string name="langauge_german">德文 (Deutsch)</string>
<string name="language_italian">義大利文 (Italiano)</string>
<string name="language_spanish">西班牙文 (Español)</string>
<string name="language_chinese">中文 (简体中文)</string>
<string name="language_korean">韓文 (한국어)</string>
<string name="language_dutch">荷蘭文 (Nederlands)</string>
<string name="language_portuguese">葡萄牙文 (Português)</string>
<string name="language_russian">俄文 (Русский)</string>
<string name="language_taiwanese">台文 (台灣)</string>
<string name="language_british_english">英式英文</string>
<string name="language_canadian_french">加拿大法文 (Français canadien)</string>
<string name="language_latin_american_spanish">拉丁美洲西班牙文 (Español latinoamericano)</string>
<string name="language_simplified_chinese">簡體中文 (简体中文)</string>
<string name="language_traditional_chinese">正體中文 (正體中文)</string>
<string name="language_brazilian_portuguese">巴西葡萄牙文 (Português do Brasil)</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>

View File

@ -113,6 +113,8 @@
<string name="install_game_content_success_install">%1$d installed successfully</string>
<string name="install_game_content_success_overwrite">%1$d overwritten successfully</string>
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
<string name="custom_driver_not_supported">Custom drivers not supported</string>
<string name="custom_driver_not_supported_description">Custom driver loading isn\'t currently supported for this device.\nCheck this option again in the future to see if support was added!</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia isn\'t real</string>
@ -230,7 +232,7 @@
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Your ROM is encrypted</string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Please follow the guides to redump your <a href="https://yuzu-emu.org/help/quickstart/#dumping-cartridge-games">game cartidges</a> or <a href="https://yuzu-emu.org/help/quickstart/#dumping-installed-titles-eshop">installed titles</a>.]]></string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Please follow the guides to redump your <a href="https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards">game cartidges</a> or <a href="https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop">installed titles</a>.]]></string>
<string name="loader_error_encrypted_keys_description"><![CDATA[Please ensure your <a href="https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys">prod.keys</a> file is installed so that games can be decrypted.]]></string>
<string name="loader_error_video_core">An error occurred initializing the video core</string>
<string name="loader_error_video_core_description">This is usually caused by an incompatible GPU driver. Installing a custom GPU driver may resolve this problem.</string>
@ -285,24 +287,24 @@
<string name="region_taiwan">Taiwan</string>
<!-- Language Names -->
<string name="language_japanese">Japanese (日本語)</string>
<string name="language_english">English</string>
<string name="language_french">French (Français)</string>
<string name="langauge_german">German (Deutsch)</string>
<string name="language_italian">Italian (Italiano)</string>
<string name="language_spanish">Spanish (Español)</string>
<string name="language_chinese">Chinese (简体中文)</string>
<string name="language_korean">Korean (한국어)</string>
<string name="language_dutch">Dutch (Nederlands)</string>
<string name="language_portuguese">Portuguese (Português)</string>
<string name="language_russian">Russian (Русский)</string>
<string name="language_taiwanese">Taiwanese (台湾)</string>
<string name="language_british_english">British English</string>
<string name="language_canadian_french">Canadian French (Français canadien)</string>
<string name="language_latin_american_spanish">Latin American Spanish (Español latinoamericano)</string>
<string name="language_simplified_chinese">Simplified Chinese (简体中文)</string>
<string name="language_traditional_chinese">Traditional Chinese (正體中文)</string>
<string name="language_brazilian_portuguese">Brazilian Portuguese (Português do Brasil)</string>
<string name="language_japanese" translatable="false">日本語</string>
<string name="language_english" translatable="false">English</string>
<string name="language_french" translatable="false">Français</string>
<string name="langauge_german" translatable="false">Deutsch</string>
<string name="language_italian" translatable="false">Italiano</string>
<string name="language_spanish" translatable="false">Español</string>
<string name="language_chinese" translatable="false">简体中文</string>
<string name="language_korean" translatable="false">한국어</string>
<string name="language_dutch" translatable="false">Nederlands</string>
<string name="language_portuguese" translatable="false">Português</string>
<string name="language_russian" translatable="false">Русский</string>
<string name="language_taiwanese" translatable="false">台湾</string>
<string name="language_british_english" translatable="false">British English</string>
<string name="language_canadian_french" translatable="false">Français canadien</string>
<string name="language_latin_american_spanish" translatable="false">Español latinoamericano</string>
<string name="language_simplified_chinese" translatable="false">简体中文</string>
<string name="language_traditional_chinese" translatable="false">正體中文</string>
<string name="language_brazilian_portuguese" translatable="false">Português do Brasil</string>
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>

View File

@ -92,9 +92,9 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
if (type == Sink::StreamType::In) {
stream->AppendBuffer(new_buffer, tmp_samples);
} else {
system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(),
buffer.size);
stream->AppendBuffer(new_buffer, tmp_samples);
Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
system.ApplicationMemory(), buffer.samples, buffer.size / sizeof(s16));
stream->AppendBuffer(new_buffer, samples);
}
}
}

View File

@ -28,7 +28,6 @@ constexpr std::array<u8, 3> PitchBySrcQuality = {4, 8, 4};
template <typename T>
static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
const DecodeArg& req) {
std::array<T, TempBufferSize> tmp_samples{};
constexpr s32 min{std::numeric_limits<s16>::min()};
constexpr s32 max{std::numeric_limits<s16>::max()};
@ -49,19 +48,18 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
const VAddr source{req.buffer +
(((req.start_offset + req.offset) * channel_count) * sizeof(T))};
const u64 size{channel_count * samples_to_decode};
const u64 size_bytes{size * sizeof(T)};
memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes);
Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
memory, source, size);
if constexpr (std::is_floating_point_v<T>) {
for (u32 i = 0; i < samples_to_decode; i++) {
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
std::numeric_limits<s16>::max())};
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
}
} else {
for (u32 i = 0; i < samples_to_decode; i++) {
out_buffer[i] = tmp_samples[i * channel_count + req.target_channel];
out_buffer[i] = samples[i * channel_count + req.target_channel];
}
}
} break;
@ -74,16 +72,17 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
}
const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T));
Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
memory, source, samples_to_decode);
if constexpr (std::is_floating_point_v<T>) {
for (u32 i = 0; i < samples_to_decode; i++) {
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
std::numeric_limits<s16>::max())};
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
}
} else {
std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16));
std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16));
}
break;
}
@ -101,7 +100,6 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
*/
static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
const DecodeArg& req) {
std::array<u8, TempBufferSize> wavebuffer{};
constexpr u32 SamplesPerFrame{14};
constexpr u32 NibblesPerFrame{16};
@ -139,7 +137,8 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
}
const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size);
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> wavebuffer(
memory, req.buffer + position_in_frame / 2, size);
auto context{req.adpcm_context};
auto header{context->header};

View File

@ -21,23 +21,13 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
}
AuxInfo::AuxInfoDsp info{};
auto info_ptr{&info};
bool host_safe{(aux_info & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp))};
memory.ReadBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp));
if (host_safe) [[likely]] {
info_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(aux_info);
} else {
memory.ReadBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
info.read_offset = 0;
info.write_offset = 0;
info.total_sample_count = 0;
info_ptr->read_offset = 0;
info_ptr->write_offset = 0;
info_ptr->total_sample_count = 0;
if (!host_safe) [[unlikely]] {
memory.WriteBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
memory.WriteBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp));
}
/**
@ -86,17 +76,9 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
}
AuxInfo::AuxInfoDsp send_info{};
auto send_ptr = &send_info;
bool host_safe = (send_info_ & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
memory.ReadBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
if (host_safe) [[likely]] {
send_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(send_info_);
} else {
memory.ReadBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
u32 target_write_offset{send_ptr->write_offset + write_offset};
u32 target_write_offset{send_info.write_offset + write_offset};
if (target_write_offset > count_max) {
return 0;
}
@ -105,15 +87,9 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
u32 read_pos{0};
while (write_count > 0) {
u32 to_write{std::min(count_max - target_write_offset, write_count)};
const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
bool write_safe{(write_addr & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - (write_addr + to_write * sizeof(s32)))};
if (write_safe) [[likely]] {
auto ptr = memory.GetPointer(write_addr);
std::memcpy(ptr, &input[read_pos], to_write * sizeof(s32));
} else {
memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
&input[read_pos], to_write * sizeof(s32));
if (to_write > 0) {
const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
memory.WriteBlockUnsafe(write_addr, &input[read_pos], to_write * sizeof(s32));
}
target_write_offset = (target_write_offset + to_write) % count_max;
write_count -= to_write;
@ -121,13 +97,10 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
}
if (update_count) {
send_ptr->write_offset = (send_ptr->write_offset + update_count) % count_max;
}
if (!host_safe) [[unlikely]] {
memory.WriteBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
send_info.write_offset = (send_info.write_offset + update_count) % count_max;
}
memory.WriteBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
return write_count_;
}
@ -174,17 +147,9 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
}
AuxInfo::AuxInfoDsp return_info{};
auto return_ptr = &return_info;
bool host_safe = (return_info_ & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
memory.ReadBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
if (host_safe) [[likely]] {
return_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(return_info_);
} else {
memory.ReadBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
u32 target_read_offset{return_ptr->read_offset + read_offset};
u32 target_read_offset{return_info.read_offset + read_offset};
if (target_read_offset > count_max) {
return 0;
}
@ -193,15 +158,9 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
u32 write_pos{0};
while (read_count > 0) {
u32 to_read{std::min(count_max - target_read_offset, read_count)};
const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
bool read_safe{(read_addr & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - (read_addr + to_read * sizeof(s32)))};
if (read_safe) [[likely]] {
auto ptr = memory.GetPointer(read_addr);
std::memcpy(&output[write_pos], ptr, to_read * sizeof(s32));
} else {
memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
&output[write_pos], to_read * sizeof(s32));
if (to_read > 0) {
const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
memory.ReadBlockUnsafe(read_addr, &output[write_pos], to_read * sizeof(s32));
}
target_read_offset = (target_read_offset + to_read) % count_max;
read_count -= to_read;
@ -209,13 +168,10 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
}
if (update_count) {
return_ptr->read_offset = (return_ptr->read_offset + update_count) % count_max;
}
if (!host_safe) [[unlikely]] {
memory.WriteBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
return_info.read_offset = (return_info.read_offset + update_count) % count_max;
}
memory.WriteBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
return read_count_;
}

View File

@ -23,7 +23,7 @@ std::string DemangleSymbol(const std::string& mangled) {
SCOPE_EXIT({ std::free(demangled); });
if (is_itanium(mangled)) {
demangled = llvm::itaniumDemangle(mangled.c_str(), nullptr, nullptr, nullptr);
demangled = llvm::itaniumDemangle(mangled.c_str());
}
if (!demangled) {

View File

@ -30,8 +30,8 @@ DetachedTasks::~DetachedTasks() {
void DetachedTasks::AddTask(std::function<void()> task) {
std::unique_lock lock{instance->mutex};
++instance->count;
std::thread([task{std::move(task)}]() {
task();
std::thread([task_{std::move(task)}]() {
task_();
std::unique_lock thread_lock{instance->mutex};
--instance->count;
std::notify_all_at_thread_exit(instance->cv, std::move(thread_lock));

View File

@ -66,6 +66,7 @@ void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page
<< (address_space_width_in_bits - page_size_in_bits)};
pointers.resize(num_page_table_entries);
backing_addr.resize(num_page_table_entries);
blocks.resize(num_page_table_entries);
current_address_space_width_in_bits = address_space_width_in_bits;
page_size = 1ULL << page_size_in_bits;
}

View File

@ -51,7 +51,7 @@ struct PageTable {
class PageInfo {
public:
/// Returns the page pointer
[[nodiscard]] u8* Pointer() const noexcept {
[[nodiscard]] uintptr_t Pointer() const noexcept {
return ExtractPointer(raw.load(std::memory_order_relaxed));
}
@ -61,7 +61,7 @@ struct PageTable {
}
/// Returns the page pointer and attribute pair, extracted from the same atomic read
[[nodiscard]] std::pair<u8*, PageType> PointerType() const noexcept {
[[nodiscard]] std::pair<uintptr_t, PageType> PointerType() const noexcept {
const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed);
return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)};
}
@ -73,13 +73,13 @@ struct PageTable {
}
/// Write a page pointer and type pair atomically
void Store(u8* pointer, PageType type) noexcept {
raw.store(reinterpret_cast<uintptr_t>(pointer) | static_cast<uintptr_t>(type));
void Store(uintptr_t pointer, PageType type) noexcept {
raw.store(pointer | static_cast<uintptr_t>(type));
}
/// Unpack a pointer from a page info raw representation
[[nodiscard]] static u8* ExtractPointer(uintptr_t raw) noexcept {
return reinterpret_cast<u8*>(raw & (~uintptr_t{0} << ATTRIBUTE_BITS));
[[nodiscard]] static uintptr_t ExtractPointer(uintptr_t raw) noexcept {
return raw & (~uintptr_t{0} << ATTRIBUTE_BITS);
}
/// Unpack a page type from a page info raw representation
@ -122,6 +122,7 @@ struct PageTable {
* corresponding attribute element is of type `Memory`.
*/
VirtualBuffer<PageInfo> pointers;
VirtualBuffer<u64> blocks;
VirtualBuffer<u64> backing_addr;

View File

@ -40,8 +40,21 @@ public:
~ScratchBuffer() = default;
ScratchBuffer(const ScratchBuffer&) = delete;
ScratchBuffer& operator=(const ScratchBuffer&) = delete;
ScratchBuffer(ScratchBuffer&&) = default;
ScratchBuffer& operator=(ScratchBuffer&&) = default;
ScratchBuffer(ScratchBuffer&& other) noexcept {
swap(other);
other.last_requested_size = 0;
other.buffer_capacity = 0;
other.buffer.reset();
}
ScratchBuffer& operator=(ScratchBuffer&& other) noexcept {
swap(other);
other.last_requested_size = 0;
other.buffer_capacity = 0;
other.buffer.reset();
return *this;
}
/// This will only grow the buffer's capacity if size is greater than the current capacity.
/// The previously held data will remain intact.

View File

@ -26,9 +26,10 @@ std::string GetTimeZoneString() {
std::string location_name;
if (time_zone_index == 0) { // Auto
#if __cpp_lib_chrono >= 201907L
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
#if __cpp_lib_chrono >= 201907L && !defined(MINGW)
// Disabled for MinGW -- tzdb always returns Etc/UTC
try {
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
std::string_view current_zone_name = current_zone->name();
location_name = current_zone_name;

View File

@ -3,17 +3,22 @@
#pragma once
#include <optional>
#include <string>
#include "common/common_types.h"
namespace Network {
/// Address families
enum class Domain : u8 {
INET, ///< Address family for IPv4
Unspecified, ///< Represents 0, used in getaddrinfo hints
INET, ///< Address family for IPv4
};
/// Socket types
enum class Type {
Unspecified, ///< Represents 0, used in getaddrinfo hints
STREAM,
DGRAM,
RAW,
@ -22,6 +27,7 @@ enum class Type {
/// Protocol values for sockets
enum class Protocol : u8 {
Unspecified, ///< Represents 0, usable in various places
ICMP,
TCP,
UDP,
@ -48,4 +54,13 @@ constexpr u32 FLAG_MSG_PEEK = 0x2;
constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
constexpr u32 FLAG_O_NONBLOCK = 0x800;
/// Cross-platform addrinfo structure
struct AddrInfo {
Domain family;
Type socket_type;
Protocol protocol;
SockAddrIn addr;
std::optional<std::string> canon_name;
};
} // namespace Network

View File

@ -4,13 +4,13 @@
#include <chrono>
#include <exception>
#include <iomanip>
#include <map>
#include <sstream>
#include <stdexcept>
#include <fmt/chrono.h>
#include <fmt/core.h>
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/time_zone.h"
namespace Common::TimeZone {
@ -33,32 +33,29 @@ std::string GetDefaultTimeZone() {
return "GMT";
}
static std::string GetOsTimeZoneOffset() {
const std::time_t t{std::time(nullptr)};
const std::tm tm{*std::localtime(&t)};
return fmt::format("{:%z}", tm);
}
static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) {
try {
return std::stoi(timezone);
} catch (const std::invalid_argument&) {
LOG_CRITICAL(Common, "invalid_argument with {}!", timezone);
return 0;
} catch (const std::out_of_range&) {
LOG_CRITICAL(Common, "out_of_range with {}!", timezone);
return 0;
}
// Results are not comparable to seconds since Epoch
static std::time_t TmSpecToSeconds(const struct std::tm& spec) {
const int year = spec.tm_year - 1; // Years up to now
const int leap_years = year / 4 - year / 100;
std::time_t cumulative = spec.tm_year;
cumulative = cumulative * 365 + leap_years + spec.tm_yday; // Years to days
cumulative = cumulative * 24 + spec.tm_hour; // Days to hours
cumulative = cumulative * 60 + spec.tm_min; // Hours to minutes
cumulative = cumulative * 60 + spec.tm_sec; // Minutes to seconds
return cumulative;
}
std::chrono::seconds GetCurrentOffsetSeconds() {
const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())};
const std::time_t t{std::time(nullptr)};
const std::tm local{*std::localtime(&t)};
const std::tm gmt{*std::gmtime(&t)};
int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds
seconds += (offset % 100) * 60; // Convert minute component to seconds
// gmt_seconds is a different offset than time(nullptr)
const auto gmt_seconds = TmSpecToSeconds(gmt);
const auto local_seconds = TmSpecToSeconds(local);
const auto seconds_offset = local_seconds - gmt_seconds;
return std::chrono::seconds{seconds};
return std::chrono::seconds{seconds_offset};
}
// Key is [Hours * 100 + Minutes], multiplied by 100 if DST
@ -71,11 +68,6 @@ const static std::map<s64, const char*> off_timezones = {
};
std::string FindSystemTimeZone() {
#if defined(MINGW)
// MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
// e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
return timezones[0];
#else
const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count());
const s64 minutes = seconds / 60;
@ -97,7 +89,6 @@ std::string FindSystemTimeZone() {
}
}
return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours));
#endif
}
} // namespace Common::TimeZone

View File

@ -285,6 +285,7 @@ add_library(core STATIC
hle/kernel/kernel.cpp
hle/kernel/kernel.h
hle/kernel/memory_types.h
hle/kernel/message_buffer.h
hle/kernel/physical_core.cpp
hle/kernel/physical_core.h
hle/kernel/physical_memory.h
@ -722,6 +723,7 @@ add_library(core STATIC
hle/service/spl/spl_types.h
hle/service/ssl/ssl.cpp
hle/service/ssl/ssl.h
hle/service/ssl/ssl_backend.h
hle/service/time/clock_types.h
hle/service/time/ephemeral_network_system_clock_context_writer.h
hle/service/time/ephemeral_network_system_clock_core.h
@ -863,6 +865,23 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_link_libraries(core PRIVATE dynarmic::dynarmic)
endif()
if(ENABLE_OPENSSL)
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_openssl.cpp)
target_link_libraries(core PRIVATE OpenSSL::SSL)
elseif (APPLE)
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_securetransport.cpp)
target_link_libraries(core PRIVATE "-framework Security")
elseif (WIN32)
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_schannel.cpp)
target_link_libraries(core PRIVATE crypt32 secur32)
else()
target_sources(core PRIVATE
hle/service/ssl/ssl_backend_none.cpp)
endif()
if (YUZU_USE_PRECOMPILED_HEADERS)
target_precompile_headers(core PRIVATE precompiled_headers.h)
endif()

View File

@ -185,7 +185,7 @@ void ARM_Interface::Run() {
// Notify the debugger and go to sleep if a breakpoint was hit,
// or if the thread is unable to continue for any reason.
if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
if (!True(hr & HaltReason::InstructionBreakpoint)) {
if (!True(hr & HaltReason::PrefetchAbort)) {
RewindBreakpointInstruction();
}
if (system.DebuggerEnabled()) {
@ -217,8 +217,8 @@ void ARM_Interface::Run() {
}
}
void ARM_Interface::LoadWatchpointArray(const WatchpointArray& wp) {
watchpoints = &wp;
void ARM_Interface::LoadWatchpointArray(const WatchpointArray* wp) {
watchpoints = wp;
}
const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint(

View File

@ -186,7 +186,7 @@ public:
virtual void SaveContext(ThreadContext64& ctx) const = 0;
virtual void LoadContext(const ThreadContext32& ctx) = 0;
virtual void LoadContext(const ThreadContext64& ctx) = 0;
void LoadWatchpointArray(const WatchpointArray& wp);
void LoadWatchpointArray(const WatchpointArray* wp);
/// Clears the exclusive monitor's state.
virtual void ClearExclusiveState() = 0;

View File

@ -346,11 +346,11 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
}
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
DynarmicExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_)
: ARM_Interface{system_, 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_)},
null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;

View File

@ -12,7 +12,7 @@
#include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h"
#include "core/arm/exclusive_monitor.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
namespace Core::Memory {
class Memory;
@ -28,8 +28,8 @@ class System;
class ARM_Dynarmic_32 final : public ARM_Interface {
public:
ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_);
ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
~ARM_Dynarmic_32() override;
void SetPC(u64 pc) override;

View File

@ -405,11 +405,11 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
}
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
DynarmicExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_)
: ARM_Interface{system_, uses_wall_clock_},
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;

View File

@ -11,7 +11,7 @@
#include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h"
#include "core/arm/exclusive_monitor.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
namespace Core::Memory {
class Memory;
@ -25,8 +25,8 @@ class System;
class ARM_Dynarmic_64 final : public ARM_Interface {
public:
ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_);
ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
~ARM_Dynarmic_64() override;
void SetPC(u64 pc) override;

View File

@ -6,8 +6,6 @@
#include <dynarmic/interface/exclusive_monitor.h>
#include "common/common_types.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#include "core/arm/exclusive_monitor.h"
namespace Core::Memory {
@ -16,6 +14,9 @@ class Memory;
namespace Core {
class ARM_Dynarmic_32;
class ARM_Dynarmic_64;
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public:
explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_);

View File

@ -880,6 +880,14 @@ const FileSys::ContentProvider& System::GetContentProvider() const {
return *impl->content_provider;
}
FileSys::ContentProviderUnion& System::GetContentProviderUnion() {
return *impl->content_provider;
}
const FileSys::ContentProviderUnion& System::GetContentProviderUnion() const {
return *impl->content_provider;
}
Service::FileSystem::FileSystemController& System::GetFileSystemController() {
return impl->fs_controller;
}

View File

@ -381,6 +381,9 @@ public:
[[nodiscard]] FileSys::ContentProvider& GetContentProvider();
[[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const;
[[nodiscard]] FileSys::ContentProviderUnion& GetContentProviderUnion();
[[nodiscard]] const FileSys::ContentProviderUnion& GetContentProviderUnion() const;
[[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController();
[[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;

View File

@ -70,7 +70,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) {
timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
}
}
@ -255,7 +255,6 @@ void CoreTiming::ThreadLoop() {
#ifdef _WIN32
while (!paused && !event.IsSet() && wait_time > 0) {
wait_time = *next_time - GetGlobalTimeNs().count();
if (wait_time >= timer_resolution_ns) {
Common::Windows::SleepForOneTick();
} else {

View File

@ -163,7 +163,7 @@ private:
Common::Event pause_event{};
std::mutex basic_lock;
std::mutex advance_lock;
std::unique_ptr<std::thread> timer_thread;
std::unique_ptr<std::jthread> timer_thread;
std::atomic<bool> paused{};
std::atomic<bool> paused_set{};
std::atomic<bool> wait_set{};

View File

@ -261,10 +261,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))};
const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))};
if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
std::vector<u8> mem(size);
system.ApplicationMemory().ReadBlock(addr, mem.data(), size);
std::vector<u8> mem(size);
if (system.ApplicationMemory().ReadBlock(addr, mem.data(), size)) {
SendReply(Common::HexToString(mem));
} else {
SendReply(GDB_STUB_REPLY_ERR);
@ -281,8 +279,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
const auto mem_substr{std::string_view(command).substr(mem_sep)};
const auto mem{Common::HexStringToVector(mem_substr, false)};
if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
system.ApplicationMemory().WriteBlock(addr, mem.data(), size);
if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) {
system.InvalidateCpuInstructionCacheRange(addr, size);
SendReply(GDB_STUB_REPLY_OK);
} else {
@ -556,7 +553,7 @@ void GDBStub::HandleQuery(std::string_view command) {
} else {
SendReply(fmt::format(
"TextSeg={:x}",
GetInteger(system.ApplicationProcess()->PageTable().GetCodeRegionStart())));
GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart())));
}
} else if (command.starts_with("Xfer:libraries:read::")) {
Loader::AppLoader::Modules modules;
@ -731,7 +728,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
std::string reply;
auto* process = system.ApplicationProcess();
auto& page_table = process->PageTable();
auto& page_table = process->GetPageTable();
const char* commands = "Commands:\n"
" get fastmem\n"

View File

@ -57,11 +57,34 @@ struct NCASectionHeaderBlock {
};
static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
struct NCABucketInfo {
u64 table_offset;
u64 table_size;
std::array<u8, 0x10> table_header;
};
static_assert(sizeof(NCABucketInfo) == 0x20, "NCABucketInfo has incorrect size.");
struct NCASparseInfo {
NCABucketInfo bucket;
u64 physical_offset;
u16 generation;
INSERT_PADDING_BYTES_NOINIT(0x6);
};
static_assert(sizeof(NCASparseInfo) == 0x30, "NCASparseInfo has incorrect size.");
struct NCACompressionInfo {
NCABucketInfo bucket;
INSERT_PADDING_BYTES_NOINIT(0x8);
};
static_assert(sizeof(NCACompressionInfo) == 0x28, "NCACompressionInfo has incorrect size.");
struct NCASectionRaw {
NCASectionHeaderBlock header;
std::array<u8, 0x138> block_data;
std::array<u8, 0x8> section_ctr;
INSERT_PADDING_BYTES_NOINIT(0xB8);
NCASparseInfo sparse_info;
NCACompressionInfo compression_info;
INSERT_PADDING_BYTES_NOINIT(0x60);
};
static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size.");
@ -225,6 +248,20 @@ bool NCA::ReadSections(const std::vector<NCASectionHeader>& sections, u64 bktr_b
for (std::size_t i = 0; i < sections.size(); ++i) {
const auto& section = sections[i];
if (section.raw.sparse_info.bucket.table_offset != 0 &&
section.raw.sparse_info.bucket.table_size != 0) {
LOG_ERROR(Loader, "Sparse NCAs are not supported.");
status = Loader::ResultStatus::ErrorSparseNCA;
return false;
}
if (section.raw.compression_info.bucket.table_offset != 0 &&
section.raw.compression_info.bucket.table_size != 0) {
LOG_ERROR(Loader, "Compressed NCAs are not supported.");
status = Loader::ResultStatus::ErrorCompressedNCA;
return false;
}
if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
if (!ReadRomFSSection(section, header.section_tables[i], bktr_base_ivfc_offset)) {
return false;

View File

@ -15,8 +15,8 @@ void KAutoObject::RegisterWithKernel() {
m_kernel.RegisterKernelObject(this);
}
void KAutoObject::UnregisterWithKernel() {
m_kernel.UnregisterKernelObject(this);
void KAutoObject::UnregisterWithKernel(KernelCore& kernel, KAutoObject* self) {
kernel.UnregisterKernelObject(self);
}
} // namespace Kernel

View File

@ -159,14 +159,15 @@ public:
// If ref count hits zero, destroy the object.
if (cur_ref_count - 1 == 0) {
KernelCore& kernel = m_kernel;
this->Destroy();
this->UnregisterWithKernel();
KAutoObject::UnregisterWithKernel(kernel, this);
}
}
private:
void RegisterWithKernel();
void UnregisterWithKernel();
static void UnregisterWithKernel(KernelCore& kernel, KAutoObject* self);
protected:
KernelCore& m_kernel;

View File

@ -25,7 +25,7 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, KProcessAddres
m_owner = GetCurrentProcessPointer(m_kernel);
// Get the owner page table.
auto& page_table = m_owner->PageTable();
auto& page_table = m_owner->GetPageTable();
// Construct the page group.
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
@ -53,7 +53,7 @@ void KCodeMemory::Finalize() {
// Unlock.
if (!m_is_mapped && !m_is_owner_mapped) {
const size_t size = m_page_group->GetNumPages() * PageSize;
m_owner->PageTable().UnlockForCodeMemory(m_address, size, *m_page_group);
m_owner->GetPageTable().UnlockForCodeMemory(m_address, size, *m_page_group);
}
// Close the page group.
@ -75,7 +75,7 @@ Result KCodeMemory::Map(KProcessAddress address, size_t size) {
R_UNLESS(!m_is_mapped, ResultInvalidState);
// Map the memory.
R_TRY(GetCurrentProcess(m_kernel).PageTable().MapPageGroup(
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
@ -92,8 +92,8 @@ Result KCodeMemory::Unmap(KProcessAddress address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(GetCurrentProcess(m_kernel).PageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::CodeOut));
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::CodeOut));
// Mark ourselves as unmapped.
m_is_mapped = false;
@ -126,8 +126,8 @@ Result KCodeMemory::MapToOwner(KProcessAddress address, size_t size, Svc::Memory
}
// Map the memory.
R_TRY(m_owner->PageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode,
k_perm));
R_TRY(m_owner->GetPageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode,
k_perm));
// Mark ourselves as mapped.
m_is_owner_mapped = true;
@ -143,7 +143,8 @@ Result KCodeMemory::UnmapFromOwner(KProcessAddress address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(m_owner->PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode));
R_TRY(m_owner->GetPageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::GeneratedCode));
// Mark ourselves as unmapped.
m_is_owner_mapped = false;

View File

@ -388,39 +388,6 @@ public:
constexpr size_t GetHeapSize() const {
return m_current_heap_end - m_heap_region_start;
}
constexpr bool IsInsideAddressSpace(KProcessAddress address, size_t size) const {
return m_address_space_start <= address && address + size - 1 <= m_address_space_end - 1;
}
constexpr bool IsOutsideAliasRegion(KProcessAddress address, size_t size) const {
return m_alias_region_start > address || address + size - 1 > m_alias_region_end - 1;
}
constexpr bool IsOutsideStackRegion(KProcessAddress address, size_t size) const {
return m_stack_region_start > address || address + size - 1 > m_stack_region_end - 1;
}
constexpr bool IsInvalidRegion(KProcessAddress address, size_t size) const {
return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1;
}
constexpr bool IsInsideHeapRegion(KProcessAddress address, size_t size) const {
return address + size > m_heap_region_start && m_heap_region_end > address;
}
constexpr bool IsInsideAliasRegion(KProcessAddress address, size_t size) const {
return address + size > m_alias_region_start && m_alias_region_end > address;
}
constexpr bool IsOutsideASLRRegion(KProcessAddress address, size_t size) const {
if (IsInvalidRegion(address, size)) {
return true;
}
if (IsInsideHeapRegion(address, size)) {
return true;
}
if (IsInsideAliasRegion(address, size)) {
return true;
}
return {};
}
constexpr bool IsInsideASLRRegion(KProcessAddress address, size_t size) const {
return !IsOutsideASLRRegion(address, size);
}
constexpr size_t GetNumGuardPages() const {
return IsKernel() ? 1 : 4;
}
@ -436,6 +403,14 @@ public:
return m_address_space_start <= addr && addr < addr + size &&
addr + size - 1 <= m_address_space_end - 1;
}
constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const {
return this->Contains(addr, size) && m_alias_region_start <= addr &&
addr + size - 1 <= m_alias_region_end - 1;
}
constexpr bool IsInHeapRegion(KProcessAddress addr, size_t size) const {
return this->Contains(addr, size) && m_heap_region_start <= addr &&
addr + size - 1 <= m_heap_region_end - 1;
}
public:
static KVirtualAddress GetLinearMappedVirtualAddress(const KMemoryLayout& layout,

View File

@ -38,7 +38,7 @@ namespace {
*/
void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority,
KProcessAddress stack_top) {
const KProcessAddress entry_point = owner_process.PageTable().GetCodeRegionStart();
const KProcessAddress entry_point = owner_process.GetPageTable().GetCodeRegionStart();
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
KThread* thread = KThread::Create(system.Kernel());

View File

@ -109,16 +109,6 @@ public:
static Result Initialize(KProcess* process, Core::System& system, std::string process_name,
ProcessType type, KResourceLimit* res_limit);
/// Gets a reference to the process' page table.
KPageTable& PageTable() {
return m_page_table;
}
/// Gets const a reference to the process' page table.
const KPageTable& PageTable() const {
return m_page_table;
}
/// Gets a reference to the process' page table.
KPageTable& GetPageTable() {
return m_page_table;

View File

@ -510,11 +510,12 @@ void KScheduler::Unload(KThread* thread) {
void KScheduler::Reload(KThread* thread) {
auto& cpu_core = m_kernel.System().ArmInterface(m_core_id);
auto* process = thread->GetOwnerProcess();
cpu_core.LoadContext(thread->GetContext32());
cpu_core.LoadContext(thread->GetContext64());
cpu_core.SetTlsAddress(GetInteger(thread->GetTlsAddress()));
cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0());
cpu_core.LoadWatchpointArray(thread->GetOwnerProcess()->GetWatchpoints());
cpu_core.LoadWatchpointArray(process ? &process->GetWatchpoints() : nullptr);
cpu_core.ClearExclusiveState();
}

View File

@ -20,12 +20,132 @@
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/message_buffer.h"
#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/memory.h"
namespace Kernel {
namespace {
template <bool MoveHandleAllowed>
Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, KThread& src_thread,
MessageBuffer& dst_msg, const MessageBuffer& src_msg,
MessageBuffer::SpecialHeader& src_special_header) {
// Copy the special header to the destination.
s32 offset = dst_msg.Set(src_special_header);
// Copy the process ID.
if (src_special_header.GetHasProcessId()) {
offset = dst_msg.SetProcessId(offset, src_process.GetProcessId());
}
// Prepare to process handles.
auto& dst_handle_table = dst_process.GetHandleTable();
auto& src_handle_table = src_process.GetHandleTable();
Result result = ResultSuccess;
// Process copy handles.
for (auto i = 0; i < src_special_header.GetCopyHandleCount(); ++i) {
// Get the handles.
const Handle src_handle = src_msg.GetHandle(offset);
Handle dst_handle = Svc::InvalidHandle;
// If we're in a success state, try to move the handle to the new table.
if (R_SUCCEEDED(result) && src_handle != Svc::InvalidHandle) {
KScopedAutoObject obj =
src_handle_table.GetObjectForIpc(src_handle, std::addressof(src_thread));
if (obj.IsNotNull()) {
Result add_result =
dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe());
if (R_FAILED(add_result)) {
result = add_result;
dst_handle = Svc::InvalidHandle;
}
} else {
result = ResultInvalidHandle;
}
}
// Set the handle.
offset = dst_msg.SetHandle(offset, dst_handle);
}
// Process move handles.
if constexpr (MoveHandleAllowed) {
for (auto i = 0; i < src_special_header.GetMoveHandleCount(); ++i) {
// Get the handles.
const Handle src_handle = src_msg.GetHandle(offset);
Handle dst_handle = Svc::InvalidHandle;
// Whether or not we've succeeded, we need to remove the handles from the source table.
if (src_handle != Svc::InvalidHandle) {
if (R_SUCCEEDED(result)) {
KScopedAutoObject obj =
src_handle_table.GetObjectForIpcWithoutPseudoHandle(src_handle);
if (obj.IsNotNull()) {
Result add_result = dst_handle_table.Add(std::addressof(dst_handle),
obj.GetPointerUnsafe());
src_handle_table.Remove(src_handle);
if (R_FAILED(add_result)) {
result = add_result;
dst_handle = Svc::InvalidHandle;
}
} else {
result = ResultInvalidHandle;
}
} else {
src_handle_table.Remove(src_handle);
}
}
// Set the handle.
offset = dst_msg.SetHandle(offset, dst_handle);
}
}
R_RETURN(result);
}
void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) {
// Parse the message.
const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
const MessageBuffer::MessageHeader dst_header(dst_msg);
const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header);
// Check that the size is big enough.
if (MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) > dst_buffer_size) {
return;
}
// Set the special header.
int offset = dst_msg.Set(dst_special_header);
// Clear the process id, if needed.
if (dst_special_header.GetHasProcessId()) {
offset = dst_msg.SetProcessId(offset, 0);
}
// Clear handles, as relevant.
auto& dst_handle_table = dst_process.GetHandleTable();
for (auto i = 0;
i < (dst_special_header.GetCopyHandleCount() + dst_special_header.GetMoveHandleCount());
++i) {
const Handle handle = dst_msg.GetHandle(offset);
if (handle != Svc::InvalidHandle) {
dst_handle_table.Remove(handle);
}
offset = dst_msg.SetHandle(offset, Svc::InvalidHandle);
}
}
} // namespace
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
KServerSession::KServerSession(KernelCore& kernel)
@ -223,12 +343,27 @@ Result KServerSession::SendReply(bool is_hle) {
// the reply has already been written in this case.
} else {
Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
KThread* server_thread = GetCurrentThreadPointer(m_kernel);
KProcess& src_process = *client_thread->GetOwnerProcess();
KProcess& dst_process = *server_thread->GetOwnerProcess();
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
auto* dst_msg_buffer = memory.GetPointer(client_message);
auto* src_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
auto* dst_msg_buffer = memory.GetPointer<u32>(client_message);
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
// Translate special header ad-hoc.
MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
MessageBuffer::MessageHeader src_header(src_msg);
MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
if (src_header.GetHasSpecialHeader()) {
MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
result = ProcessMessageSpecialData<true>(dst_process, src_process, *server_thread,
dst_msg, src_msg, src_special_header);
if (R_FAILED(result)) {
CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
}
}
}
} else {
result = ResultSessionClosed;
@ -330,12 +465,28 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
cmd_buf);
} else {
KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
KThread* server_thread = GetCurrentThreadPointer(m_kernel);
KProcess& src_process = *client_thread->GetOwnerProcess();
KProcess& dst_process = *server_thread->GetOwnerProcess();
UNIMPLEMENTED_IF(client_thread->GetOwnerProcess() != server_thread->GetOwnerProcess());
auto* src_msg_buffer = memory.GetPointer(client_message);
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
auto* src_msg_buffer = memory.GetPointer<u32>(client_message);
auto* dst_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
// Translate special header ad-hoc.
// TODO: fix this mess
MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
MessageBuffer::MessageHeader src_header(src_msg);
MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
if (src_header.GetHasSpecialHeader()) {
MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
Result res = ProcessMessageSpecialData<false>(dst_process, src_process, *client_thread,
dst_msg, src_msg, src_special_header);
if (R_FAILED(res)) {
CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
}
}
}
// We succeeded.

View File

@ -90,8 +90,8 @@ Result KSharedMemory::Map(KProcess& target_process, KProcessAddress address, std
R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission);
}
R_RETURN(target_process.PageTable().MapPageGroup(address, *m_page_group, KMemoryState::Shared,
ConvertToKMemoryPermission(map_perm)));
R_RETURN(target_process.GetPageTable().MapPageGroup(
address, *m_page_group, KMemoryState::Shared, ConvertToKMemoryPermission(map_perm)));
}
Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address,
@ -100,7 +100,7 @@ Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address,
R_UNLESS(m_size == unmap_size, ResultInvalidSize);
R_RETURN(
target_process.PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::Shared));
target_process.GetPageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::Shared));
}
} // namespace Kernel

View File

@ -129,7 +129,7 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress
case ThreadType::User:
ASSERT(((owner == nullptr) ||
(owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask()));
ASSERT(((owner == nullptr) ||
ASSERT(((owner == nullptr) || (prio > Svc::LowestThreadPriority) ||
(owner->GetPriorityMask() | (1ULL << prio)) == owner->GetPriorityMask()));
break;
case ThreadType::Kernel:
@ -302,12 +302,12 @@ Result KThread::InitializeServiceThread(Core::System& system, KThread* thread,
std::function<void()>&& func, s32 prio, s32 virt_core,
KProcess* owner) {
system.Kernel().GlobalSchedulerContext().AddThread(thread);
std::function<void()> func2{[&system, func{std::move(func)}] {
std::function<void()> func2{[&system, func_{std::move(func)}] {
// Similar to UserModeThreadStarter.
system.Kernel().CurrentScheduler()->OnThreadStart();
// Run the guest function.
func();
func_();
// Exit.
Svc::ExitThread(system);

View File

@ -25,9 +25,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
// Map the address in.
const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
R_TRY(m_owner->PageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr,
KMemoryState::ThreadLocal,
KMemoryPermission::UserReadWrite));
R_TRY(m_owner->GetPageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr,
KMemoryState::ThreadLocal,
KMemoryPermission::UserReadWrite));
// We succeeded.
page_buf_guard.Cancel();
@ -37,11 +37,11 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
Result KThreadLocalPage::Finalize() {
// Get the physical address of the page.
const KPhysicalAddress phys_addr = m_owner->PageTable().GetPhysicalAddr(m_virt_addr);
const KPhysicalAddress phys_addr = m_owner->GetPageTable().GetPhysicalAddr(m_virt_addr);
ASSERT(phys_addr);
// Unmap the page.
R_TRY(m_owner->PageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal));
R_TRY(m_owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal));
// Free the page.
KPageBuffer::Free(*m_kernel, KPageBuffer::FromPhysicalAddress(m_kernel->System(), phys_addr));

View File

@ -1089,15 +1089,15 @@ static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process,
KThread::Register(kernel, thread);
return std::jthread(
[&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] {
[&kernel, thread, thread_name_{std::move(thread_name)}, func_{std::move(func)}] {
// Set the thread name.
Common::SetCurrentThreadName(thread_name.c_str());
Common::SetCurrentThreadName(thread_name_.c_str());
// Set the thread as current.
kernel.RegisterHostThread(thread);
// Run the callback.
func();
func_();
// Close the thread.
// This will free the process if it is the last reference.

View File

@ -0,0 +1,612 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/alignment.h"
#include "common/bit_field.h"
#include "core/hle/kernel/k_thread.h"
namespace Kernel {
constexpr inline size_t MessageBufferSize = 0x100;
class MessageBuffer {
public:
class MessageHeader {
private:
static constexpr inline u64 NullTag = 0;
public:
enum class ReceiveListCountType : u32 {
None = 0,
ToMessageBuffer = 1,
ToSingleBuffer = 2,
CountOffset = 2,
CountMax = 13,
};
private:
union {
std::array<u32, 2> raw;
struct {
// Define fields for the first header word.
union {
BitField<0, 16, u16> tag;
BitField<16, 4, u32> pointer_count;
BitField<20, 4, u32> send_count;
BitField<24, 4, u32> receive_count;
BitField<28, 4, u32> exchange_count;
};
// Define fields for the second header word.
union {
BitField<0, 10, u32> raw_count;
BitField<10, 4, ReceiveListCountType> receive_list_count;
BitField<14, 6, u32> reserved0;
BitField<20, 11, u32> receive_list_offset;
BitField<31, 1, u32> has_special_header;
};
};
} m_header;
public:
constexpr MessageHeader() : m_header{} {}
constexpr MessageHeader(u16 tag, bool special, s32 ptr, s32 send, s32 recv, s32 exch,
s32 raw, ReceiveListCountType recv_list)
: m_header{} {
m_header.raw[0] = 0;
m_header.raw[1] = 0;
m_header.tag.Assign(tag);
m_header.pointer_count.Assign(ptr);
m_header.send_count.Assign(send);
m_header.receive_count.Assign(recv);
m_header.exchange_count.Assign(exch);
m_header.raw_count.Assign(raw);
m_header.receive_list_count.Assign(recv_list);
m_header.has_special_header.Assign(special);
}
explicit MessageHeader(const MessageBuffer& buf) : m_header{} {
buf.Get(0, m_header.raw.data(), 2);
}
explicit MessageHeader(const u32* msg) : m_header{{msg[0], msg[1]}} {}
constexpr u16 GetTag() const {
return m_header.tag;
}
constexpr s32 GetPointerCount() const {
return m_header.pointer_count;
}
constexpr s32 GetSendCount() const {
return m_header.send_count;
}
constexpr s32 GetReceiveCount() const {
return m_header.receive_count;
}
constexpr s32 GetExchangeCount() const {
return m_header.exchange_count;
}
constexpr s32 GetMapAliasCount() const {
return this->GetSendCount() + this->GetReceiveCount() + this->GetExchangeCount();
}
constexpr s32 GetRawCount() const {
return m_header.raw_count;
}
constexpr ReceiveListCountType GetReceiveListCount() const {
return m_header.receive_list_count;
}
constexpr s32 GetReceiveListOffset() const {
return m_header.receive_list_offset;
}
constexpr bool GetHasSpecialHeader() const {
return m_header.has_special_header.Value() != 0;
}
constexpr void SetReceiveListCount(ReceiveListCountType recv_list) {
m_header.receive_list_count.Assign(recv_list);
}
constexpr const u32* GetData() const {
return m_header.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_header);
}
};
class SpecialHeader {
private:
union {
std::array<u32, 1> raw;
// Define fields for the header word.
BitField<0, 1, u32> has_process_id;
BitField<1, 4, u32> copy_handle_count;
BitField<5, 4, u32> move_handle_count;
} m_header;
bool m_has_header;
public:
constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move)
: m_header{}, m_has_header(true) {
m_header.has_process_id.Assign(pid);
m_header.copy_handle_count.Assign(copy);
m_header.move_handle_count.Assign(move);
}
constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move, bool _has_header)
: m_header{}, m_has_header(_has_header) {
m_header.has_process_id.Assign(pid);
m_header.copy_handle_count.Assign(copy);
m_header.move_handle_count.Assign(move);
}
explicit SpecialHeader(const MessageBuffer& buf, const MessageHeader& hdr)
: m_header{}, m_has_header(hdr.GetHasSpecialHeader()) {
if (m_has_header) {
buf.Get(static_cast<s32>(MessageHeader::GetDataSize() / sizeof(u32)),
m_header.raw.data(), sizeof(m_header) / sizeof(u32));
}
}
constexpr bool GetHasProcessId() const {
return m_header.has_process_id.Value() != 0;
}
constexpr s32 GetCopyHandleCount() const {
return m_header.copy_handle_count;
}
constexpr s32 GetMoveHandleCount() const {
return m_header.move_handle_count;
}
constexpr const u32* GetHeader() const {
return m_header.raw.data();
}
constexpr size_t GetHeaderSize() const {
if (m_has_header) {
return sizeof(m_header);
} else {
return 0;
}
}
constexpr size_t GetDataSize() const {
if (m_has_header) {
return (this->GetHasProcessId() ? sizeof(u64) : 0) +
(this->GetCopyHandleCount() * sizeof(Handle)) +
(this->GetMoveHandleCount() * sizeof(Handle));
} else {
return 0;
}
}
};
class MapAliasDescriptor {
public:
enum class Attribute : u32 {
Ipc = 0,
NonSecureIpc = 1,
NonDeviceIpc = 3,
};
private:
static constexpr u32 SizeLowCount = 32;
static constexpr u32 SizeHighCount = 4;
static constexpr u32 AddressLowCount = 32;
static constexpr u32 AddressMidCount = 4;
constexpr u32 GetAddressMid(u64 address) {
return static_cast<u32>(address >> AddressLowCount) & ((1U << AddressMidCount) - 1);
}
constexpr u32 GetAddressHigh(u64 address) {
return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
}
private:
union {
std::array<u32, 3> raw;
struct {
// Define fields for the first two words.
u32 size_low;
u32 address_low;
// Define fields for the packed descriptor word.
union {
BitField<0, 2, Attribute> attributes;
BitField<2, 3, u32> address_high;
BitField<5, 19, u32> reserved;
BitField<24, 4, u32> size_high;
BitField<28, 4, u32> address_mid;
};
};
} m_data;
public:
constexpr MapAliasDescriptor() : m_data{} {}
MapAliasDescriptor(const void* buffer, size_t _size, Attribute attr = Attribute::Ipc)
: m_data{} {
const u64 address = reinterpret_cast<u64>(buffer);
const u64 size = static_cast<u64>(_size);
m_data.size_low = static_cast<u32>(size);
m_data.address_low = static_cast<u32>(address);
m_data.attributes.Assign(attr);
m_data.address_mid.Assign(GetAddressMid(address));
m_data.size_high.Assign(static_cast<u32>(size >> SizeLowCount));
m_data.address_high.Assign(GetAddressHigh(address));
}
MapAliasDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
buf.Get(index, m_data.raw.data(), 3);
}
constexpr uintptr_t GetAddress() const {
return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
<< AddressLowCount) |
m_data.address_low;
}
constexpr uintptr_t GetSize() const {
return (static_cast<u64>(m_data.size_high) << SizeLowCount) | m_data.size_low;
}
constexpr Attribute GetAttribute() const {
return m_data.attributes;
}
constexpr const u32* GetData() const {
return m_data.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_data);
}
};
class PointerDescriptor {
private:
static constexpr u32 AddressLowCount = 32;
static constexpr u32 AddressMidCount = 4;
constexpr u32 GetAddressMid(u64 address) {
return static_cast<u32>(address >> AddressLowCount) & ((1u << AddressMidCount) - 1);
}
constexpr u32 GetAddressHigh(u64 address) {
return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
}
private:
union {
std::array<u32, 2> raw;
struct {
// Define fields for the packed descriptor word.
union {
BitField<0, 4, u32> index;
BitField<4, 2, u32> reserved0;
BitField<6, 3, u32> address_high;
BitField<9, 3, u32> reserved1;
BitField<12, 4, u32> address_mid;
BitField<16, 16, u32> size;
};
// Define fields for the second word.
u32 address_low;
};
} m_data;
public:
constexpr PointerDescriptor() : m_data{} {}
PointerDescriptor(const void* buffer, size_t size, s32 index) : m_data{} {
const u64 address = reinterpret_cast<u64>(buffer);
m_data.index.Assign(index);
m_data.address_high.Assign(GetAddressHigh(address));
m_data.address_mid.Assign(GetAddressMid(address));
m_data.size.Assign(static_cast<u32>(size));
m_data.address_low = static_cast<u32>(address);
}
PointerDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
buf.Get(index, m_data.raw.data(), 2);
}
constexpr s32 GetIndex() const {
return m_data.index;
}
constexpr uintptr_t GetAddress() const {
return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
<< AddressLowCount) |
m_data.address_low;
}
constexpr size_t GetSize() const {
return m_data.size;
}
constexpr const u32* GetData() const {
return m_data.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_data);
}
};
class ReceiveListEntry {
private:
static constexpr u32 AddressLowCount = 32;
constexpr u32 GetAddressHigh(u64 address) {
return static_cast<u32>(address >> (AddressLowCount));
}
private:
union {
std::array<u32, 2> raw;
struct {
// Define fields for the first word.
u32 address_low;
// Define fields for the packed descriptor word.
union {
BitField<0, 7, u32> address_high;
BitField<7, 9, u32> reserved;
BitField<16, 16, u32> size;
};
};
} m_data;
public:
constexpr ReceiveListEntry() : m_data{} {}
ReceiveListEntry(const void* buffer, size_t size) : m_data{} {
const u64 address = reinterpret_cast<u64>(buffer);
m_data.address_low = static_cast<u32>(address);
m_data.address_high.Assign(GetAddressHigh(address));
m_data.size.Assign(static_cast<u32>(size));
}
ReceiveListEntry(u32 a, u32 b) : m_data{{a, b}} {}
constexpr uintptr_t GetAddress() const {
return (static_cast<u64>(m_data.address_high) << AddressLowCount) | m_data.address_low;
}
constexpr size_t GetSize() const {
return m_data.size;
}
constexpr const u32* GetData() const {
return m_data.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_data);
}
};
private:
u32* m_buffer;
size_t m_size;
public:
constexpr MessageBuffer(u32* b, size_t sz) : m_buffer(b), m_size(sz) {}
constexpr explicit MessageBuffer(u32* b) : m_buffer(b), m_size(MessageBufferSize) {}
constexpr void* GetBufferForDebug() const {
return m_buffer;
}
constexpr size_t GetBufferSize() const {
return m_size;
}
void Get(s32 index, u32* dst, size_t count) const {
// Ensure that this doesn't get re-ordered.
std::atomic_thread_fence(std::memory_order_seq_cst);
// Get the words.
static_assert(sizeof(*dst) == sizeof(*m_buffer));
memcpy(dst, m_buffer + index, count * sizeof(*dst));
}
s32 Set(s32 index, u32* src, size_t count) const {
// Ensure that this doesn't get re-ordered.
std::atomic_thread_fence(std::memory_order_seq_cst);
// Set the words.
memcpy(m_buffer + index, src, count * sizeof(*src));
// Ensure that this doesn't get re-ordered.
std::atomic_thread_fence(std::memory_order_seq_cst);
return static_cast<s32>(index + count);
}
template <typename T>
const T& GetRaw(s32 index) const {
return *reinterpret_cast<const T*>(m_buffer + index);
}
template <typename T>
s32 SetRaw(s32 index, const T& val) const {
*reinterpret_cast<const T*>(m_buffer + index) = val;
return index + (Common::AlignUp(sizeof(val), sizeof(*m_buffer)) / sizeof(*m_buffer));
}
void GetRawArray(s32 index, void* dst, size_t len) const {
memcpy(dst, m_buffer + index, len);
}
void SetRawArray(s32 index, const void* src, size_t len) const {
memcpy(m_buffer + index, src, len);
}
void SetNull() const {
this->Set(MessageHeader());
}
s32 Set(const MessageHeader& hdr) const {
memcpy(m_buffer, hdr.GetData(), hdr.GetDataSize());
return static_cast<s32>(hdr.GetDataSize() / sizeof(*m_buffer));
}
s32 Set(const SpecialHeader& spc) const {
const s32 index = static_cast<s32>(MessageHeader::GetDataSize() / sizeof(*m_buffer));
memcpy(m_buffer + index, spc.GetHeader(), spc.GetHeaderSize());
return static_cast<s32>(index + (spc.GetHeaderSize() / sizeof(*m_buffer)));
}
s32 SetHandle(s32 index, const Handle& hnd) const {
memcpy(m_buffer + index, std::addressof(hnd), sizeof(hnd));
return static_cast<s32>(index + (sizeof(hnd) / sizeof(*m_buffer)));
}
s32 SetProcessId(s32 index, const u64 pid) const {
memcpy(m_buffer + index, std::addressof(pid), sizeof(pid));
return static_cast<s32>(index + (sizeof(pid) / sizeof(*m_buffer)));
}
s32 Set(s32 index, const MapAliasDescriptor& desc) const {
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
}
s32 Set(s32 index, const PointerDescriptor& desc) const {
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
}
s32 Set(s32 index, const ReceiveListEntry& desc) const {
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
}
s32 Set(s32 index, const u32 val) const {
memcpy(m_buffer + index, std::addressof(val), sizeof(val));
return static_cast<s32>(index + (sizeof(val) / sizeof(*m_buffer)));
}
Result GetAsyncResult() const {
MessageHeader hdr(m_buffer);
MessageHeader null{};
if (memcmp(hdr.GetData(), null.GetData(), MessageHeader::GetDataSize()) != 0) [[unlikely]] {
R_SUCCEED();
}
return Result(m_buffer[MessageHeader::GetDataSize() / sizeof(*m_buffer)]);
}
void SetAsyncResult(Result res) const {
const s32 index = this->Set(MessageHeader());
const auto value = res.raw;
memcpy(m_buffer + index, std::addressof(value), sizeof(value));
}
u32 Get32(s32 index) const {
return m_buffer[index];
}
u64 Get64(s32 index) const {
u64 value;
memcpy(std::addressof(value), m_buffer + index, sizeof(value));
return value;
}
u64 GetProcessId(s32 index) const {
return this->Get64(index);
}
Handle GetHandle(s32 index) const {
static_assert(sizeof(Handle) == sizeof(*m_buffer));
return Handle(m_buffer[index]);
}
static constexpr s32 GetSpecialDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
return static_cast<s32>((MessageHeader::GetDataSize() / sizeof(u32)) +
(spc.GetHeaderSize() / sizeof(u32)));
}
static constexpr s32 GetPointerDescriptorIndex(const MessageHeader& hdr,
const SpecialHeader& spc) {
return static_cast<s32>(GetSpecialDataIndex(hdr, spc) + (spc.GetDataSize() / sizeof(u32)));
}
static constexpr s32 GetMapAliasDescriptorIndex(const MessageHeader& hdr,
const SpecialHeader& spc) {
return GetPointerDescriptorIndex(hdr, spc) +
static_cast<s32>(hdr.GetPointerCount() * PointerDescriptor::GetDataSize() /
sizeof(u32));
}
static constexpr s32 GetRawDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
return GetMapAliasDescriptorIndex(hdr, spc) +
static_cast<s32>(hdr.GetMapAliasCount() * MapAliasDescriptor::GetDataSize() /
sizeof(u32));
}
static constexpr s32 GetReceiveListIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
if (const s32 recv_list_index = hdr.GetReceiveListOffset()) {
return recv_list_index;
} else {
return GetRawDataIndex(hdr, spc) + hdr.GetRawCount();
}
}
static constexpr size_t GetMessageBufferSize(const MessageHeader& hdr,
const SpecialHeader& spc) {
// Get the size of the plain message.
size_t msg_size = GetReceiveListIndex(hdr, spc) * sizeof(u32);
// Add the size of the receive list.
const auto count = hdr.GetReceiveListCount();
switch (count) {
case MessageHeader::ReceiveListCountType::None:
break;
case MessageHeader::ReceiveListCountType::ToMessageBuffer:
break;
case MessageHeader::ReceiveListCountType::ToSingleBuffer:
msg_size += ReceiveListEntry::GetDataSize();
break;
default:
msg_size += (static_cast<s32>(count) -
static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
ReceiveListEntry::GetDataSize();
break;
}
return msg_size;
}
};
} // namespace Kernel

View File

@ -17,7 +17,9 @@ PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KSchedu
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
auto& kernel = system.Kernel();
m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index);
system, kernel.IsMulticore(),
reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
m_core_index);
#else
#error Platform not supported yet.
#endif
@ -31,7 +33,9 @@ void PhysicalCore::Initialize(bool is_64_bit) {
if (!is_64_bit) {
// We already initialized a 64-bit core, replace with a 32-bit one.
m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
m_system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index);
m_system, kernel.IsMulticore(),
reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
m_core_index);
}
#else
#error Platform not supported yet.

View File

@ -42,7 +42,7 @@ Result FlushProcessDataCache(Core::System& system, Handle process_handle, u64 ad
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Verify the region is within range.
auto& page_table = process->PageTable();
auto& page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Perform the operation.

View File

@ -48,7 +48,7 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t
SCOPE_EXIT({ code_mem->Close(); });
// Verify that the region is in range.
R_UNLESS(GetCurrentProcess(system.Kernel()).PageTable().Contains(address, size),
R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
ResultInvalidCurrentMemory);
// Initialize the code memory.
@ -92,7 +92,7 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
case CodeMemoryOperation::Map: {
// Check that the region is in range.
R_UNLESS(GetCurrentProcess(system.Kernel())
.PageTable()
.GetPageTable()
.CanContain(address, size, KMemoryState::CodeOut),
ResultInvalidMemoryRegion);
@ -105,7 +105,7 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
case CodeMemoryOperation::Unmap: {
// Check that the region is in range.
R_UNLESS(GetCurrentProcess(system.Kernel())
.PageTable()
.GetPageTable()
.CanContain(address, size, KMemoryState::CodeOut),
ResultInvalidMemoryRegion);
@ -117,8 +117,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
} break;
case CodeMemoryOperation::MapToOwner: {
// Check that the region is in range.
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
KMemoryState::GeneratedCode),
R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size,
KMemoryState::GeneratedCode),
ResultInvalidMemoryRegion);
// Check the memory permission.
@ -129,8 +129,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
} break;
case CodeMemoryOperation::UnmapFromOwner: {
// Check that the region is in range.
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
KMemoryState::GeneratedCode),
R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size,
KMemoryState::GeneratedCode),
ResultInvalidMemoryRegion);
// Check the memory permission.

View File

@ -107,7 +107,7 @@ Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Han
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the process address is within range.
auto& page_table = process->PageTable();
auto& page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
// Map.
@ -148,7 +148,7 @@ Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Han
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the process address is within range.
auto& page_table = process->PageTable();
auto& page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
// Map.
@ -180,7 +180,7 @@ Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle p
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the process address is within range.
auto& page_table = process->PageTable();
auto& page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
R_RETURN(das->Unmap(std::addressof(page_table), process_address, size, device_address));

View File

@ -54,35 +54,35 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
R_SUCCEED();
case InfoType::AliasRegionAddress:
*result = GetInteger(process->PageTable().GetAliasRegionStart());
*result = GetInteger(process->GetPageTable().GetAliasRegionStart());
R_SUCCEED();
case InfoType::AliasRegionSize:
*result = process->PageTable().GetAliasRegionSize();
*result = process->GetPageTable().GetAliasRegionSize();
R_SUCCEED();
case InfoType::HeapRegionAddress:
*result = GetInteger(process->PageTable().GetHeapRegionStart());
*result = GetInteger(process->GetPageTable().GetHeapRegionStart());
R_SUCCEED();
case InfoType::HeapRegionSize:
*result = process->PageTable().GetHeapRegionSize();
*result = process->GetPageTable().GetHeapRegionSize();
R_SUCCEED();
case InfoType::AslrRegionAddress:
*result = GetInteger(process->PageTable().GetAliasCodeRegionStart());
*result = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
R_SUCCEED();
case InfoType::AslrRegionSize:
*result = process->PageTable().GetAliasCodeRegionSize();
*result = process->GetPageTable().GetAliasCodeRegionSize();
R_SUCCEED();
case InfoType::StackRegionAddress:
*result = GetInteger(process->PageTable().GetStackRegionStart());
*result = GetInteger(process->GetPageTable().GetStackRegionStart());
R_SUCCEED();
case InfoType::StackRegionSize:
*result = process->PageTable().GetStackRegionSize();
*result = process->GetPageTable().GetStackRegionSize();
R_SUCCEED();
case InfoType::TotalMemorySize:

View File

@ -8,6 +8,7 @@
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
@ -49,14 +50,10 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad
// Copy user handles.
if (num_handles > 0) {
// Ensure we can try to get the handles.
R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
ResultInvalidPointer);
// Get the handles.
GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(),
sizeof(Handle) * num_handles);
R_UNLESS(GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(),
sizeof(Handle) * num_handles),
ResultInvalidPointer);
// Convert the handles to objects.
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(

View File

@ -63,36 +63,13 @@ Result MapUnmapMemorySanityChecks(const KPageTable& manager, u64 dst_addr, u64 s
R_THROW(ResultInvalidCurrentMemory);
}
if (!manager.IsInsideAddressSpace(src_addr, size)) {
if (!manager.Contains(src_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
src_addr, size);
R_THROW(ResultInvalidCurrentMemory);
}
if (manager.IsOutsideStackRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
dst_addr, size);
R_THROW(ResultInvalidMemoryRegion);
}
if (manager.IsInsideHeapRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination does not fit within the heap region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
R_THROW(ResultInvalidMemoryRegion);
}
if (manager.IsInsideAliasRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination does not fit within the map region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
R_THROW(ResultInvalidMemoryRegion);
}
R_SUCCEED();
}
@ -112,7 +89,7 @@ Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPe
R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Validate that the region is in range for the current process.
auto& page_table = GetCurrentProcess(system.Kernel()).PageTable();
auto& page_table = GetCurrentProcess(system.Kernel()).GetPageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory attribute.
@ -136,7 +113,7 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask,
R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination);
// Validate that the region is in range for the current process.
auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()};
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory attribute.
@ -148,7 +125,7 @@ Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) {
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()};
if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
result.IsError()) {
@ -163,7 +140,7 @@ Result UnmapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) {
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()};
if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
result.IsError()) {

View File

@ -16,7 +16,7 @@ Result SetHeapSize(Core::System& system, u64* out_address, u64 size) {
R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize);
// Set the heap size.
R_RETURN(GetCurrentProcess(system.Kernel()).PageTable().SetHeapSize(out_address, size));
R_RETURN(GetCurrentProcess(system.Kernel()).GetPageTable().SetHeapSize(out_address, size));
}
/// Maps memory at a desired address
@ -44,21 +44,21 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) {
}
KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
auto& page_table{current_process->PageTable()};
auto& page_table{current_process->GetPageTable()};
if (current_process->GetSystemResourceSize() == 0) {
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
R_THROW(ResultInvalidState);
}
if (!page_table.IsInsideAddressSpace(addr, size)) {
if (!page_table.Contains(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
R_THROW(ResultInvalidMemoryRegion);
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
if (!page_table.IsInAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);
@ -93,21 +93,21 @@ Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) {
}
KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
auto& page_table{current_process->PageTable()};
auto& page_table{current_process->GetPageTable()};
if (current_process->GetSystemResourceSize() == 0) {
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
R_THROW(ResultInvalidState);
}
if (!page_table.IsInsideAddressSpace(addr, size)) {
if (!page_table.Contains(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
R_THROW(ResultInvalidMemoryRegion);
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
if (!page_table.IsInAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);

View File

@ -66,8 +66,8 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc
auto& kernel = system.Kernel();
const auto total_copy_size = out_process_ids_size * sizeof(u64);
if (out_process_ids_size > 0 && !GetCurrentProcess(kernel).PageTable().IsInsideAddressSpace(
out_process_ids, total_copy_size)) {
if (out_process_ids_size > 0 &&
!GetCurrentProcess(kernel).GetPageTable().Contains(out_process_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_process_ids, out_process_ids + total_copy_size);
R_THROW(ResultInvalidCurrentMemory);

View File

@ -49,7 +49,7 @@ Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the address is in range.
auto& page_table = process->PageTable();
auto& page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory permission.
@ -77,8 +77,8 @@ Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_ha
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
// Get the page tables.
auto& dst_pt = dst_process->PageTable();
auto& src_pt = src_process->PageTable();
auto& dst_pt = dst_process->GetPageTable();
auto& src_pt = src_process->GetPageTable();
// Validate that the mapping is in range.
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
@ -118,8 +118,8 @@ Result UnmapProcessMemory(Core::System& system, u64 dst_address, Handle process_
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
// Get the page tables.
auto& dst_pt = dst_process->PageTable();
auto& src_pt = src_process->PageTable();
auto& dst_pt = dst_process->GetPageTable();
auto& src_pt = src_process->GetPageTable();
// Validate that the mapping is in range.
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
@ -178,8 +178,8 @@ Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst
R_THROW(ResultInvalidHandle);
}
auto& page_table = process->PageTable();
if (!page_table.IsInsideAddressSpace(src_address, size)) {
auto& page_table = process->GetPageTable();
if (!page_table.Contains(src_address, size)) {
LOG_ERROR(Kernel_SVC,
"Source address range is not within the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
@ -187,14 +187,6 @@ Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst
R_THROW(ResultInvalidCurrentMemory);
}
if (!page_table.IsInsideASLRRegion(dst_address, size)) {
LOG_ERROR(Kernel_SVC,
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
R_THROW(ResultInvalidMemoryRegion);
}
R_RETURN(page_table.MapCodeMemory(dst_address, src_address, size));
}
@ -246,8 +238,8 @@ Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 d
R_THROW(ResultInvalidHandle);
}
auto& page_table = process->PageTable();
if (!page_table.IsInsideAddressSpace(src_address, size)) {
auto& page_table = process->GetPageTable();
if (!page_table.Contains(src_address, size)) {
LOG_ERROR(Kernel_SVC,
"Source address range is not within the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
@ -255,14 +247,6 @@ Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 d
R_THROW(ResultInvalidCurrentMemory);
}
if (!page_table.IsInsideASLRRegion(dst_address, size)) {
LOG_ERROR(Kernel_SVC,
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
R_THROW(ResultInvalidMemoryRegion);
}
R_RETURN(page_table.UnmapCodeMemory(dst_address, src_address, size,
KPageTable::ICacheInvalidationStrategy::InvalidateAll));
}

View File

@ -31,7 +31,7 @@ Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageIn
}
auto& current_memory{GetCurrentMemory(system.Kernel())};
const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()};
const auto memory_info{process->GetPageTable().QueryInfo(address).GetSvcMemoryInfo()};
current_memory.WriteBlock(out_memory_info, std::addressof(memory_info), sizeof(memory_info));

View File

@ -43,7 +43,7 @@ Result MapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, u
// Get the current process.
auto& process = GetCurrentProcess(system.Kernel());
auto& page_table = process.PageTable();
auto& page_table = process.GetPageTable();
// Get the shared memory.
KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
@ -73,7 +73,7 @@ Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, u64 address,
// Get the current process.
auto& process = GetCurrentProcess(system.Kernel());
auto& page_table = process.PageTable();
auto& page_table = process.GetPageTable();
// Get the shared memory.
KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);

View File

@ -7,6 +7,7 @@
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
@ -64,14 +65,10 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha
// Copy user handles.
if (num_handles > 0) {
// Ensure we can try to get the handles.
R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
user_handles, static_cast<u64>(sizeof(Handle) * num_handles)),
ResultInvalidPointer);
// Get the handles.
GetCurrentMemory(kernel).ReadBlock(user_handles, handles.data(),
sizeof(Handle) * num_handles);
R_UNLESS(GetCurrentMemory(kernel).ReadBlock(user_handles, handles.data(),
sizeof(Handle) * num_handles),
ResultInvalidPointer);
// Convert the handles to objects.
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(

View File

@ -236,7 +236,7 @@ Result GetThreadList(Core::System& system, s32* out_num_threads, u64 out_thread_
const auto total_copy_size = out_thread_ids_size * sizeof(u64);
if (out_thread_ids_size > 0 &&
!current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) {
!current_process->GetPageTable().Contains(out_thread_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_thread_ids, out_thread_ids + total_copy_size);
R_THROW(ResultInvalidCurrentMemory);

View File

@ -55,7 +55,7 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
SCOPE_EXIT({ trmem->Close(); });
// Ensure that the region is in range.
R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory);
R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
// Initialize the transfer memory.
R_TRY(trmem->Initialize(address, size, map_perm));

View File

@ -496,8 +496,9 @@ public:
void LoadIdTokenCache(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
protected:

View File

@ -506,8 +506,8 @@ void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
idle_time_detection_extension = rp.Pop<u32>();
LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
idle_time_detection_extension);
LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
idle_time_detection_extension);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -2,13 +2,48 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/glue/ectx.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::Glue {
// This is nn::err::context::IContextRegistrar
class IContextRegistrar : public ServiceFramework<IContextRegistrar> {
public:
IContextRegistrar(Core::System& system_) : ServiceFramework{system_, "IContextRegistrar"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IContextRegistrar::Complete, "Complete"},
};
// clang-format on
RegisterHandlers(functions);
}
~IContextRegistrar() override = default;
private:
void Complete(HLERequestContext& ctx) {
struct InputParameters {
u32 unk;
};
struct OutputParameters {
u32 unk;
};
IPC::RequestParser rp{ctx};
[[maybe_unused]] auto input = rp.PopRaw<InputParameters>();
[[maybe_unused]] auto value = ctx.ReadBuffer();
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
};
ECTX_AW::ECTX_AW(Core::System& system_) : ServiceFramework{system_, "ectx:aw"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateContextRegistrar"},
{0, &ECTX_AW::CreateContextRegistrar, "CreateContextRegistrar"},
{1, nullptr, "CommitContext"},
};
// clang-format on
@ -18,4 +53,10 @@ ECTX_AW::ECTX_AW(Core::System& system_) : ServiceFramework{system_, "ectx:aw"} {
ECTX_AW::~ECTX_AW() = default;
void ECTX_AW::CreateContextRegistrar(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IContextRegistrar>(std::make_shared<IContextRegistrar>(system));
}
} // namespace Service::Glue

View File

@ -15,6 +15,9 @@ class ECTX_AW final : public ServiceFramework<ECTX_AW> {
public:
explicit ECTX_AW(Core::System& system_);
~ECTX_AW() override;
private:
void CreateContextRegistrar(HLERequestContext& ctx);
};
} // namespace Service::Glue

View File

@ -329,8 +329,22 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
}
std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a;
static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x;
static thread_local std::array read_buffer_a{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
static thread_local std::array read_buffer_data_a{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
static thread_local std::array read_buffer_data_x{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
BufferDescriptorA()[buffer_index].Size()};
@ -339,19 +353,17 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
BufferDescriptorA().size() > buffer_index, { return {}; },
"BufferDescriptorA invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_a[buffer_index];
read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(),
read_buffer.size());
return read_buffer;
return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(),
BufferDescriptorA()[buffer_index].Size(),
&read_buffer_data_a[buffer_index]);
} else {
ASSERT_OR_EXECUTE_MSG(
BufferDescriptorX().size() > buffer_index, { return {}; },
"BufferDescriptorX invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_x[buffer_index];
read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(),
read_buffer.size());
return read_buffer;
return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(),
BufferDescriptorX()[buffer_index].Size(),
&read_buffer_data_x[buffer_index]);
}
}

View File

@ -318,15 +318,15 @@ public:
return false;
}
if (!page_table.IsInsideAddressSpace(out_addr, size)) {
if (!page_table.Contains(out_addr, size)) {
return false;
}
if (page_table.IsInsideHeapRegion(out_addr, size)) {
if (page_table.IsInHeapRegion(out_addr, size)) {
return false;
}
if (page_table.IsInsideAliasRegion(out_addr, size)) {
if (page_table.IsInAliasRegion(out_addr, size)) {
return false;
}
@ -358,7 +358,7 @@ public:
}
ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) {
auto& page_table{process->PageTable()};
auto& page_table{process->GetPageTable()};
VAddr addr{};
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
@ -382,7 +382,7 @@ public:
ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
VAddr bss_addr, std::size_t bss_size, std::size_t size) {
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
auto& page_table{process->PageTable()};
auto& page_table{process->GetPageTable()};
VAddr addr{};
CASCADE_RESULT(addr, MapProcessCodeMemory(process, nro_addr, nro_size));
@ -437,12 +437,12 @@ public:
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
nro_header.segment_headers[DATA_INDEX].memory_size);
CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
return process->PageTable().SetProcessMemoryPermission(
return process->GetPageTable().SetProcessMemoryPermission(
data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite);
}
@ -571,7 +571,7 @@ public:
Result UnmapNro(const NROInfo& info) {
// Each region must be unmapped separately to validate memory state
auto& page_table{system.ApplicationProcess()->PageTable()};
auto& page_table{system.ApplicationProcess()->GetPageTable()};
if (info.bss_size != 0) {
CASCADE_CODE(page_table.UnmapCodeMemory(
@ -643,7 +643,7 @@ public:
initialized = true;
current_map_addr =
GetInteger(system.ApplicationProcess()->PageTable().GetAliasCodeRegionStart());
GetInteger(system.ApplicationProcess()->GetPageTable().GetAliasCodeRegionStart());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -180,7 +180,7 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
}
void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
const std::vector<u8>& seed) {
std::span<const u8> seed) {
// Initialize context
ctx.used = false;
ctx.counter = 0;

View File

@ -75,7 +75,7 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
// Initializes mbedtls context
void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
const std::vector<u8>& seed);
std::span<const u8> seed);
// Feeds data to mbedtls context to generate the derived key
void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output);

View File

@ -34,8 +34,6 @@
#include "core/hle/service/nfc/mifare_result.h"
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/time_manager.h"
#include "core/hle/service/time/time_zone_content_manager.h"
#include "core/hle/service/time/time_zone_types.h"
namespace Service::NFC {
NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
@ -1486,6 +1484,7 @@ DeviceState NfcDevice::GetCurrentState() const {
}
Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const {
// TODO: This should get the npad id from nn::hid::system::GetXcdHandleForNpadWithNfc
out_npad_id = npad_id;
return ResultSuccess;
}

View File

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm>
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hid/hid_types.h"
@ -10,6 +12,7 @@
#include "core/hle/service/nfc/common/device_manager.h"
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/time_manager.h"
namespace Service::NFC {
@ -51,22 +54,53 @@ Result DeviceManager::Finalize() {
return ResultSuccess;
}
Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices,
std::size_t max_allowed_devices) const {
Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices,
bool skip_fatal_errors) const {
std::scoped_lock lock{mutex};
if (max_allowed_devices < 1) {
return ResultInvalidArgument;
}
Result result = IsNfcParameterSet();
if (result.IsError()) {
return result;
}
result = IsNfcEnabled();
if (result.IsError()) {
return result;
}
result = IsNfcInitialized();
if (result.IsError()) {
return result;
}
for (auto& device : devices) {
if (nfp_devices.size() >= max_allowed_devices) {
continue;
}
if (device->GetCurrentState() != DeviceState::Unavailable) {
nfp_devices.push_back(device->GetHandle());
if (skip_fatal_errors) {
constexpr u64 MinimumRecoveryTime = 60;
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point -
time_since_last_error;
if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
continue;
}
}
if (device->GetCurrentState() == DeviceState::Unavailable) {
continue;
}
nfp_devices.push_back(device->GetHandle());
}
if (nfp_devices.empty()) {
return ResultDeviceNotFound;
}
return ResultSuccess;
return result;
}
DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
@ -79,10 +113,10 @@ DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
return device->GetCurrentState();
}
return DeviceState::Unavailable;
return DeviceState::Finalized;
}
Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const {
Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -128,7 +162,7 @@ Result DeviceManager::StopDetection(u64 device_handle) {
return result;
}
Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const {
Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -142,24 +176,46 @@ Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const {
return result;
}
Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const {
std::scoped_lock lock{mutex};
Result DeviceManager::AttachActivateEvent(Kernel::KReadableEvent** out_event,
u64 device_handle) const {
std::vector<u64> nfp_devices;
std::shared_ptr<NfcDevice> device = nullptr;
GetDeviceFromHandle(device_handle, device, false);
Result result = ListDevices(nfp_devices, 9, false);
// TODO: Return proper error code on failure
return device->GetActivateEvent();
if (result.IsSuccess()) {
result = CheckHandleOnList(device_handle, nfp_devices);
}
if (result.IsSuccess()) {
result = GetDeviceFromHandle(device_handle, device, false);
}
if (result.IsSuccess()) {
*out_event = &device->GetActivateEvent();
}
return result;
}
Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const {
std::scoped_lock lock{mutex};
Result DeviceManager::AttachDeactivateEvent(Kernel::KReadableEvent** out_event,
u64 device_handle) const {
std::vector<u64> nfp_devices;
std::shared_ptr<NfcDevice> device = nullptr;
GetDeviceFromHandle(device_handle, device, false);
Result result = ListDevices(nfp_devices, 9, false);
// TODO: Return proper error code on failure
return device->GetDeactivateEvent();
if (result.IsSuccess()) {
result = CheckHandleOnList(device_handle, nfp_devices);
}
if (result.IsSuccess()) {
result = GetDeviceFromHandle(device_handle, device, false);
}
if (result.IsSuccess()) {
*out_event = &device->GetDeactivateEvent();
}
return result;
}
Result DeviceManager::ReadMifare(u64 device_handle,
@ -253,7 +309,7 @@ Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
return result;
}
Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const {
Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -324,7 +380,7 @@ Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
return result;
}
Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const {
Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -338,7 +394,7 @@ Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& regi
return result;
}
Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const {
Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -352,7 +408,7 @@ Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_i
return result;
}
Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const {
Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -399,7 +455,7 @@ Result DeviceManager::Format(u64 device_handle) {
return result;
}
Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const {
Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -414,7 +470,7 @@ Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info
}
Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
NFP::RegisterInfoPrivate& register_info) const {
NFP::RegisterInfoPrivate& register_info) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -471,7 +527,7 @@ Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
return result;
}
Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const {
Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -485,7 +541,7 @@ Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_applica
return result;
}
Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const {
Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -541,7 +597,7 @@ Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
return result;
}
Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const {
Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
@ -593,6 +649,19 @@ Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<cons
return result;
}
Result DeviceManager::CheckHandleOnList(u64 device_handle,
const std::span<const u64> device_list) const {
if (device_list.size() < 1) {
return ResultDeviceNotFound;
}
if (std::find(device_list.begin(), device_list.end(), device_handle) != device_list.end()) {
return ResultSuccess;
}
return ResultDeviceNotFound;
}
Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
bool check_state) const {
if (check_state) {
@ -647,7 +716,7 @@ Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& de
}
Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
Result operation_result) const {
Result operation_result) {
if (operation_result.IsSuccess()) {
return operation_result;
}
@ -669,6 +738,12 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
return device_state;
}
if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 ||
operation_result == ResultUnknown115) {
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point;
}
return operation_result;
}

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