Compare commits

...

75 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
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
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
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
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
138 changed files with 5488 additions and 3271 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

@ -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

@ -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

@ -232,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>
@ -287,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

@ -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

@ -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

View File

@ -26,7 +26,8 @@ std::string GetTimeZoneString() {
std::string location_name;
if (time_zone_index == 0) { // Auto
#if __cpp_lib_chrono >= 201907L
#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();

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

@ -723,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
@ -864,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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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;
}

View File

@ -27,15 +27,16 @@ public:
// Nfc device manager
Result Initialize();
Result Finalize();
Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const;
Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices,
bool skip_fatal_errors) const;
DeviceState GetDeviceState(u64 device_handle) const;
Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const;
Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id);
Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
Result StopDetection(u64 device_handle);
Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const;
Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info);
Result AttachActivateEvent(Kernel::KReadableEvent** event, u64 device_handle) const;
Result AttachDeactivateEvent(Kernel::KReadableEvent** event, u64 device_handle) const;
Result ReadMifare(u64 device_handle,
const std::span<const MifareReadBlockParameter> read_parameters,
std::span<MifareReadBlockData> read_data);
@ -48,28 +49,28 @@ public:
Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);
Result Unmount(u64 device_handle);
Result OpenApplicationArea(u64 device_handle, u32 access_id);
Result GetApplicationArea(u64 device_handle, std::span<u8> data) const;
Result GetApplicationArea(u64 device_handle, std::span<u8> data);
Result SetApplicationArea(u64 device_handle, std::span<const u8> data);
Result Flush(u64 device_handle);
Result Restore(u64 device_handle);
Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const;
Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const;
Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const;
Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info);
Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info);
Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info);
u32 GetApplicationAreaSize() const;
Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
Result Format(u64 device_handle);
Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const;
Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const;
Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info);
Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info);
Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info);
Result DeleteRegisterInfo(u64 device_handle);
Result DeleteApplicationArea(u64 device_handle);
Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const;
Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const;
Result ExistsApplicationArea(u64 device_handle, bool& has_application_area);
Result GetAll(u64 device_handle, NFP::NfpData& nfp_data);
Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data);
Result FlushDebug(u64 device_handle);
Result BreakTag(u64 device_handle, NFP::BreakType break_type);
Result ReadBackupData(u64 device_handle, std::span<u8> data) const;
Result ReadBackupData(u64 device_handle, std::span<u8> data);
Result WriteBackupData(u64 device_handle, std::span<const u8> data);
Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data);
@ -78,17 +79,20 @@ private:
Result IsNfcParameterSet() const;
Result IsNfcInitialized() const;
Result CheckHandleOnList(u64 device_handle, std::span<const u64> device_list) const;
Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device,
bool check_state) const;
Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const;
Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const;
Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result);
Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const;
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
bool is_initialized = false;
u64 time_since_last_error = 0;
mutable std::mutex mutex;
std::array<std::shared_ptr<NfcDevice>, 10> devices{};

View File

@ -79,7 +79,7 @@ void NfcInterface::ListDevices(HLERequestContext& ctx) {
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
LOG_DEBUG(Service_NFC, "called");
auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices);
auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices, true);
result = TranslateResultToServiceError(result);
if (result.IsError()) {
@ -190,9 +190,13 @@ void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
const auto device_handle{rp.Pop<u64>()};
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
Kernel::KReadableEvent* out_event = nullptr;
auto result = GetManager()->AttachActivateEvent(&out_event, device_handle);
result = TranslateResultToServiceError(result);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle));
rb.Push(result);
rb.PushCopyObjects(out_event);
}
void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
@ -200,9 +204,13 @@ void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
const auto device_handle{rp.Pop<u64>()};
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
Kernel::KReadableEvent* out_event = nullptr;
auto result = GetManager()->AttachDeactivateEvent(&out_event, device_handle);
result = TranslateResultToServiceError(result);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle));
rb.Push(result);
rb.PushCopyObjects(out_event);
}
void NfcInterface::ReadMifare(HLERequestContext& ctx) {

View File

@ -17,7 +17,10 @@ constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88);
constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
constexpr Result ResultUnknown112(ErrorModule::NFC, 112);
constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113);
constexpr Result ResultUnknown114(ErrorModule::NFC, 114);
constexpr Result ResultUnknown115(ErrorModule::NFC, 115);
constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120);
constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128);
constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);

View File

@ -7,6 +7,7 @@
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/server_manager.h"
#include "network/network.h"
namespace {

View File

@ -4,14 +4,15 @@
#pragma once
#include "core/hle/service/service.h"
#include "network/network.h"
#include "network/room.h"
#include "network/room_member.h"
namespace Core {
class System;
}
namespace Network {
class RoomNetwork;
}
namespace Service::NIFM {
void LoopProcess(Core::System& system);

View File

@ -128,7 +128,7 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
}
bool is_out_io{};
ASSERT(system.ApplicationProcess()
->PageTable()
->GetPageTable()
.LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,
handle_description->size,
Kernel::KMemoryPermission::None, true, false)
@ -255,7 +255,7 @@ NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
if (auto freeInfo{file.FreeHandle(params.handle, false)}) {
if (freeInfo->can_unlock) {
ASSERT(system.ApplicationProcess()
->PageTable()
->GetPageTable()
.UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size)
.IsSuccess());
}

View File

@ -20,6 +20,9 @@
#include "core/internal_network/sockets.h"
#include "network/network.h"
using Common::Expected;
using Common::Unexpected;
namespace Service::Sockets {
namespace {
@ -265,16 +268,19 @@ void BSD::GetSockOpt(HLERequestContext& ctx) {
const u32 level = rp.Pop<u32>();
const auto optname = static_cast<OptName>(rp.Pop<u32>());
LOG_WARNING(Service, "(STUBBED) called. fd={} level={} optname=0x{:x}", fd, level, optname);
std::vector<u8> optval(ctx.GetWriteBufferSize());
LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} len=0x{:x}", fd, level, optname,
optval.size());
const Errno err = GetSockOptImpl(fd, level, optname, optval);
ctx.WriteBuffer(optval);
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
rb.Push<s32>(-1);
rb.PushEnum(Errno::NOTCONN);
rb.Push<s32>(err == Errno::SUCCESS ? 0 : -1);
rb.PushEnum(err);
rb.Push<u32>(static_cast<u32>(optval.size()));
}
@ -436,6 +442,31 @@ void BSD::Close(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, CloseImpl(fd));
}
void BSD::DuplicateSocket(HLERequestContext& ctx) {
struct InputParameters {
s32 fd;
u64 reserved;
};
static_assert(sizeof(InputParameters) == 0x10);
struct OutputParameters {
s32 ret;
Errno bsd_errno;
};
static_assert(sizeof(OutputParameters) == 0x8);
IPC::RequestParser rp{ctx};
auto input = rp.PopRaw<InputParameters>();
Expected<s32, Errno> res = DuplicateSocketImpl(input.fd);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushRaw(OutputParameters{
.ret = res.value_or(0),
.bsd_errno = res ? Errno::SUCCESS : res.error(),
});
}
void BSD::EventFd(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 initval = rp.Pop<u64>();
@ -477,12 +508,12 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
auto room_member = room_network.GetRoomMember().lock();
if (room_member && room_member->IsConnected()) {
descriptor.socket = std::make_unique<Network::ProxySocket>(room_network);
descriptor.socket = std::make_shared<Network::ProxySocket>(room_network);
} else {
descriptor.socket = std::make_unique<Network::Socket>();
descriptor.socket = std::make_shared<Network::Socket>();
}
descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol));
descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(protocol));
descriptor.is_connection_based = IsConnectionBased(type);
return {fd, Errno::SUCCESS};
@ -528,7 +559,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
if (!descriptor) {
LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd);
LOG_TRACE(Service, "File descriptor handle={} is not allocated", pollfd.fd);
pollfd.revents = PollEvents::Nval;
return {0, Errno::SUCCESS};
}
@ -538,7 +569,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) {
Network::PollFD result;
result.socket = file_descriptors[pollfd.fd]->socket.get();
result.events = TranslatePollEventsToHost(pollfd.events);
result.events = Translate(pollfd.events);
result.revents = Network::PollEvents{};
return result;
});
@ -547,7 +578,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
const size_t num = host_pollfds.size();
for (size_t i = 0; i < num; ++i) {
fds[i].revents = TranslatePollEventsToGuest(host_pollfds[i].revents);
fds[i].revents = Translate(host_pollfds[i].revents);
}
std::memcpy(write_buffer.data(), fds.data(), length);
@ -617,7 +648,8 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
}
const SockAddrIn guest_addrin = Translate(addr_in);
ASSERT(write_buffer.size() == sizeof(guest_addrin));
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
write_buffer.resize(sizeof(guest_addrin));
std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
return Translate(bsd_errno);
}
@ -633,7 +665,8 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
}
const SockAddrIn guest_addrin = Translate(addr_in);
ASSERT(write_buffer.size() == sizeof(guest_addrin));
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
write_buffer.resize(sizeof(guest_addrin));
std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
return Translate(bsd_errno);
}
@ -671,13 +704,47 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
}
}
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
UNIMPLEMENTED_IF(level != 0xffff); // SOL_SOCKET
Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
UNIMPLEMENTED_MSG("Unknown getsockopt level");
return Errno::SUCCESS;
}
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
switch (optname) {
case OptName::ERROR_: {
auto [pending_err, getsockopt_err] = socket->GetPendingError();
if (getsockopt_err == Network::Errno::SUCCESS) {
Errno translated_pending_err = Translate(pending_err);
ASSERT_OR_EXECUTE_MSG(
optval.size() == sizeof(Errno), { return Errno::INVAL; },
"Incorrect getsockopt option size");
optval.resize(sizeof(Errno));
memcpy(optval.data(), &translated_pending_err, sizeof(Errno));
}
return Translate(getsockopt_err);
}
default:
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
return Errno::SUCCESS;
}
}
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
UNIMPLEMENTED_MSG("Unknown setsockopt level");
return Errno::SUCCESS;
}
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
if (optname == OptName::LINGER) {
@ -711,6 +778,9 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con
return Translate(socket->SetSndTimeo(value));
case OptName::RCVTIMEO:
return Translate(socket->SetRcvTimeo(value));
case OptName::NOSIGPIPE:
LOG_WARNING(Service, "(STUBBED) setting NOSIGPIPE to {}", value);
return Errno::SUCCESS;
default:
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
return Errno::SUCCESS;
@ -841,6 +911,28 @@ Errno BSD::CloseImpl(s32 fd) {
return bsd_errno;
}
Expected<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
if (!IsFileDescriptorValid(fd)) {
return Unexpected(Errno::BADF);
}
const s32 new_fd = FindFreeFileDescriptorHandle();
if (new_fd < 0) {
LOG_ERROR(Service, "No more file descriptors available");
return Unexpected(Errno::MFILE);
}
file_descriptors[new_fd] = file_descriptors[fd];
return new_fd;
}
std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
if (!IsFileDescriptorValid(fd)) {
return std::nullopt;
}
return file_descriptors[fd]->socket;
}
s32 BSD::FindFreeFileDescriptorHandle() noexcept {
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
if (!file_descriptors[fd]) {
@ -911,7 +1003,7 @@ BSD::BSD(Core::System& system_, const char* name)
{24, &BSD::Write, "Write"},
{25, &BSD::Read, "Read"},
{26, &BSD::Close, "Close"},
{27, nullptr, "DuplicateSocket"},
{27, &BSD::DuplicateSocket, "DuplicateSocket"},
{28, nullptr, "GetResourceStatistics"},
{29, nullptr, "RecvMMsg"},
{30, nullptr, "SendMMsg"},

View File

@ -8,6 +8,7 @@
#include <vector>
#include "common/common_types.h"
#include "common/expected.h"
#include "common/socket_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sockets/sockets.h"
@ -29,12 +30,19 @@ public:
explicit BSD(Core::System& system_, const char* name);
~BSD() override;
// These methods are called from SSL; the first two are also called from
// this class for the corresponding IPC methods.
// On the real device, the SSL service makes IPC calls to this service.
Common::Expected<s32, Errno> DuplicateSocketImpl(s32 fd);
Errno CloseImpl(s32 fd);
std::optional<std::shared_ptr<Network::SocketBase>> GetSocket(s32 fd);
private:
/// Maximum number of file descriptors
static constexpr size_t MAX_FD = 128;
struct FileDescriptor {
std::unique_ptr<Network::SocketBase> socket;
std::shared_ptr<Network::SocketBase> socket;
s32 flags = 0;
bool is_connection_based = false;
};
@ -138,6 +146,7 @@ private:
void Write(HLERequestContext& ctx);
void Read(HLERequestContext& ctx);
void Close(HLERequestContext& ctx);
void DuplicateSocket(HLERequestContext& ctx);
void EventFd(HLERequestContext& ctx);
template <typename Work>
@ -153,6 +162,7 @@ private:
Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
Errno ListenImpl(s32 fd, s32 backlog);
std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval);
Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval);
Errno ShutdownImpl(s32 fd, s32 how);
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
@ -161,7 +171,6 @@ private:
std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
std::span<const u8> addr);
Errno CloseImpl(s32 fd);
s32 FindFreeFileDescriptorHandle() noexcept;
bool IsFileDescriptorValid(s32 fd) const noexcept;

View File

@ -1,22 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/sockets/nsd.h"
#include "common/string_util.h"
namespace Service::Sockets {
constexpr Result ResultOverflow{ErrorModule::NSD, 6};
// This is nn::oe::ServerEnvironmentType
enum class ServerEnvironmentType : u8 {
Dd,
Lp,
Sd,
Sp,
Dp,
};
NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
// clang-format off
static const FunctionInfo functions[] = {
{5, nullptr, "GetSettingUrl"},
{10, nullptr, "GetSettingName"},
{11, nullptr, "GetEnvironmentIdentifier"},
{11, &NSD::GetEnvironmentIdentifier, "GetEnvironmentIdentifier"},
{12, nullptr, "GetDeviceId"},
{13, nullptr, "DeleteSettings"},
{14, nullptr, "ImportSettings"},
{15, nullptr, "SetChangeEnvironmentIdentifierDisabled"},
{20, nullptr, "Resolve"},
{21, nullptr, "ResolveEx"},
{20, &NSD::Resolve, "Resolve"},
{21, &NSD::ResolveEx, "ResolveEx"},
{30, nullptr, "GetNasServiceSetting"},
{31, nullptr, "GetNasServiceSettingEx"},
{40, nullptr, "GetNasRequestFqdn"},
@ -31,7 +45,7 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
{62, nullptr, "DeleteSaveDataOfFsForTest"},
{63, nullptr, "IsChangeEnvironmentIdentifierDisabled"},
{64, nullptr, "SetWithoutDomainExchangeFqdns"},
{100, nullptr, "GetApplicationServerEnvironmentType"},
{100, &NSD::GetApplicationServerEnvironmentType, "GetApplicationServerEnvironmentType"},
{101, nullptr, "SetApplicationServerEnvironmentType"},
{102, nullptr, "DeleteApplicationServerEnvironmentType"},
};
@ -40,6 +54,69 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
RegisterHandlers(functions);
}
static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
// The real implementation makes various substitutions.
// For now we just return the string as-is, which is good enough when not
// connecting to real Nintendo servers.
LOG_WARNING(Service, "(STUBBED) called, fqdn_in={}", fqdn_in);
return fqdn_in;
}
static Result ResolveCommon(const std::string& fqdn_in, std::array<char, 0x100>& fqdn_out) {
const auto res = ResolveImpl(fqdn_in);
if (res.Failed()) {
return res.Code();
}
if (res->size() >= fqdn_out.size()) {
return ResultOverflow;
}
std::memcpy(fqdn_out.data(), res->c_str(), res->size() + 1);
return ResultSuccess;
}
void NSD::Resolve(HLERequestContext& ctx) {
const std::string fqdn_in = Common::StringFromBuffer(ctx.ReadBuffer(0));
std::array<char, 0x100> fqdn_out{};
const Result res = ResolveCommon(fqdn_in, fqdn_out);
ctx.WriteBuffer(fqdn_out);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void NSD::ResolveEx(HLERequestContext& ctx) {
const std::string fqdn_in = Common::StringFromBuffer(ctx.ReadBuffer(0));
std::array<char, 0x100> fqdn_out;
const Result res = ResolveCommon(fqdn_in, fqdn_out);
if (res.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
return;
}
ctx.WriteBuffer(fqdn_out);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(ResultSuccess);
}
void NSD::GetEnvironmentIdentifier(HLERequestContext& ctx) {
const std::string environment_identifier = "lp1";
ctx.WriteBuffer(environment_identifier);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void NSD::GetApplicationServerEnvironmentType(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(ServerEnvironmentType::Lp));
}
NSD::~NSD() = default;
} // namespace Service::Sockets

View File

@ -15,6 +15,12 @@ class NSD final : public ServiceFramework<NSD> {
public:
explicit NSD(Core::System& system_, const char* name);
~NSD() override;
private:
void Resolve(HLERequestContext& ctx);
void ResolveEx(HLERequestContext& ctx);
void GetEnvironmentIdentifier(HLERequestContext& ctx);
void GetApplicationServerEnvironmentType(HLERequestContext& ctx);
};
} // namespace Service::Sockets

View File

@ -10,39 +10,30 @@
#include "core/core.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/sockets/sfdnsres.h"
#include "core/hle/service/sockets/sockets.h"
#include "core/hle/service/sockets/sockets_translate.h"
#include "core/internal_network/network.h"
#include "core/memory.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#elif YUZU_UNIX
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#ifndef EAI_NODATA
#define EAI_NODATA EAI_NONAME
#endif
#endif
namespace Service::Sockets {
SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
static const FunctionInfo functions[] = {
{0, nullptr, "SetDnsAddressesPrivateRequest"},
{1, nullptr, "GetDnsAddressPrivateRequest"},
{2, nullptr, "GetHostByNameRequest"},
{2, &SFDNSRES::GetHostByNameRequest, "GetHostByNameRequest"},
{3, nullptr, "GetHostByAddrRequest"},
{4, nullptr, "GetHostStringErrorRequest"},
{5, nullptr, "GetGaiStringErrorRequest"},
{5, &SFDNSRES::GetGaiStringErrorRequest, "GetGaiStringErrorRequest"},
{6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"},
{7, nullptr, "GetNameInfoRequest"},
{8, nullptr, "RequestCancelHandleRequest"},
{9, nullptr, "CancelRequest"},
{10, nullptr, "GetHostByNameRequestWithOptions"},
{10, &SFDNSRES::GetHostByNameRequestWithOptions, "GetHostByNameRequestWithOptions"},
{11, nullptr, "GetHostByAddrRequestWithOptions"},
{12, &SFDNSRES::GetAddrInfoRequestWithOptions, "GetAddrInfoRequestWithOptions"},
{13, nullptr, "GetNameInfoRequestWithOptions"},
{14, nullptr, "ResolverSetOptionRequest"},
{14, &SFDNSRES::ResolverSetOptionRequest, "ResolverSetOptionRequest"},
{15, nullptr, "ResolverGetOptionRequest"},
};
RegisterHandlers(functions);
@ -59,188 +50,299 @@ enum class NetDbError : s32 {
NoData = 4,
};
static NetDbError AddrInfoErrorToNetDbError(s32 result) {
// Best effort guess to map errors
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
// These combinations have been verified on console (but are not
// exhaustive).
switch (result) {
case 0:
case GetAddrInfoError::SUCCESS:
return NetDbError::Success;
case EAI_AGAIN:
case GetAddrInfoError::AGAIN:
return NetDbError::TryAgain;
case EAI_NODATA:
return NetDbError::NoData;
case GetAddrInfoError::NODATA:
return NetDbError::HostNotFound;
case GetAddrInfoError::SERVICE:
return NetDbError::Success;
default:
return NetDbError::HostNotFound;
}
}
static std::vector<u8> SerializeAddrInfo(const addrinfo* addrinfo, s32 result_code,
static Errno GetAddrInfoErrorToErrno(GetAddrInfoError result) {
// These combinations have been verified on console (but are not
// exhaustive).
switch (result) {
case GetAddrInfoError::SUCCESS:
// Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
// some reason, but that doesn't seem useful to implement.
return Errno::SUCCESS;
case GetAddrInfoError::AGAIN:
return Errno::SUCCESS;
case GetAddrInfoError::NODATA:
return Errno::SUCCESS;
case GetAddrInfoError::SERVICE:
return Errno::INVAL;
default:
return Errno::SUCCESS;
}
}
template <typename T>
static void Append(std::vector<u8>& vec, T t) {
const size_t offset = vec.size();
vec.resize(offset + sizeof(T));
std::memcpy(vec.data() + offset, &t, sizeof(T));
}
static void AppendNulTerminated(std::vector<u8>& vec, std::string_view str) {
const size_t offset = vec.size();
vec.resize(offset + str.size() + 1);
std::memmove(vec.data() + offset, str.data(), str.size());
}
// We implement gethostbyname using the host's getaddrinfo rather than the
// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
// behaves the same on Unix and Windows, unlike gethostbyname where Windows
// doesn't implement h_errno.
static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::AddrInfo>& vec,
std::string_view host) {
std::vector<u8> data;
// h_name: use the input hostname (append nul-terminated)
AppendNulTerminated(data, host);
// h_aliases: leave empty
Append<u32_be>(data, 0); // count of h_aliases
// (If the count were nonzero, the aliases would be appended as nul-terminated here.)
Append<u16_be>(data, static_cast<u16>(Domain::INET)); // h_addrtype
Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
// h_addr_list:
size_t count = vec.size();
ASSERT(count <= UINT32_MAX);
Append<u32_be>(data, static_cast<uint32_t>(count));
for (const Network::AddrInfo& addrinfo : vec) {
// On the Switch, this is passed through htonl despite already being
// big-endian, so it ends up as little-endian.
Append<u32_le>(data, Network::IPv4AddressToInteger(addrinfo.addr.ip));
LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host,
Network::IPv4AddressToString(addrinfo.addr.ip));
}
return data;
}
static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
struct InputParameters {
u8 use_nsd_resolve;
u32 cancel_handle;
u64 process_id;
};
static_assert(sizeof(InputParameters) == 0x10);
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<InputParameters>();
LOG_WARNING(
Service,
"called with ignored parameters: use_nsd_resolve={}, cancel_handle={}, process_id={}",
parameters.use_nsd_resolve, parameters.cancel_handle, parameters.process_id);
const auto host_buffer = ctx.ReadBuffer(0);
const std::string host = Common::StringFromBuffer(host_buffer);
// For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
auto res = Network::GetAddressInfo(host, /*service*/ std::nullopt);
if (!res.has_value()) {
return {0, Translate(res.error())};
}
const std::vector<u8> data = SerializeAddrInfoAsHostEnt(res.value(), host);
const u32 data_size = static_cast<u32>(data.size());
ctx.WriteBuffer(data, 0);
return {data_size, GetAddrInfoError::SUCCESS};
}
void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
auto [data_size, emu_gai_err] = GetHostByNameRequestImpl(ctx);
struct OutputParameters {
NetDbError netdb_error;
Errno bsd_errno;
u32 data_size;
};
static_assert(sizeof(OutputParameters) == 0xc);
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
rb.PushRaw(OutputParameters{
.netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
.data_size = data_size,
});
}
void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
auto [data_size, emu_gai_err] = GetHostByNameRequestImpl(ctx);
struct OutputParameters {
u32 data_size;
NetDbError netdb_error;
Errno bsd_errno;
};
static_assert(sizeof(OutputParameters) == 0xc);
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
rb.PushRaw(OutputParameters{
.data_size = data_size,
.netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
});
}
static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& vec,
std::string_view host) {
// Adapted from
// https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
std::vector<u8> data;
auto* current = addrinfo;
while (current != nullptr) {
struct SerializedResponseHeader {
u32 magic;
s32 flags;
s32 family;
s32 socket_type;
s32 protocol;
u32 address_length;
};
static_assert(sizeof(SerializedResponseHeader) == 0x18,
"Response header size must be 0x18 bytes");
for (const Network::AddrInfo& addrinfo : vec) {
// serialized addrinfo:
Append<u32_be>(data, 0xBEEFCAFE); // magic
Append<u32_be>(data, 0); // ai_flags
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
Append<u32_be>(data, sizeof(SockAddrIn)); // ai_addrlen
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
constexpr auto header_size = sizeof(SerializedResponseHeader);
const auto addr_size =
current->ai_addr && current->ai_addrlen > 0 ? current->ai_addrlen : 4;
const auto canonname_size = current->ai_canonname ? strlen(current->ai_canonname) + 1 : 1;
// ai_addr:
Append<u16_be>(data, static_cast<u16>(Translate(addrinfo.addr.family))); // sin_family
// On the Switch, the following fields are passed through htonl despite
// already being big-endian, so they end up as little-endian.
Append<u16_le>(data, addrinfo.addr.portno); // sin_port
Append<u32_le>(data, Network::IPv4AddressToInteger(addrinfo.addr.ip)); // sin_addr
data.resize(data.size() + 8, 0); // sin_zero
const auto last_size = data.size();
data.resize(last_size + header_size + addr_size + canonname_size);
// Header in network byte order
SerializedResponseHeader header{};
constexpr auto HEADER_MAGIC = 0xBEEFCAFE;
header.magic = htonl(HEADER_MAGIC);
header.family = htonl(current->ai_family);
header.flags = htonl(current->ai_flags);
header.socket_type = htonl(current->ai_socktype);
header.protocol = htonl(current->ai_protocol);
header.address_length = current->ai_addr ? htonl((u32)current->ai_addrlen) : 0;
auto* header_ptr = data.data() + last_size;
std::memcpy(header_ptr, &header, header_size);
if (header.address_length == 0) {
std::memset(header_ptr + header_size, 0, 4);
if (addrinfo.canon_name.has_value()) {
AppendNulTerminated(data, *addrinfo.canon_name);
} else {
switch (current->ai_family) {
case AF_INET: {
struct SockAddrIn {
s16 sin_family;
u16 sin_port;
u32 sin_addr;
u8 sin_zero[8];
};
SockAddrIn serialized_addr{};
const auto addr = *reinterpret_cast<sockaddr_in*>(current->ai_addr);
serialized_addr.sin_port = htons(addr.sin_port);
serialized_addr.sin_family = htons(addr.sin_family);
serialized_addr.sin_addr = htonl(addr.sin_addr.s_addr);
std::memcpy(header_ptr + header_size, &serialized_addr, sizeof(SockAddrIn));
char addr_string_buf[64]{};
inet_ntop(AF_INET, &addr.sin_addr, addr_string_buf, std::size(addr_string_buf));
LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host, addr_string_buf);
break;
}
case AF_INET6: {
struct SockAddrIn6 {
s16 sin6_family;
u16 sin6_port;
u32 sin6_flowinfo;
u8 sin6_addr[16];
u32 sin6_scope_id;
};
SockAddrIn6 serialized_addr{};
const auto addr = *reinterpret_cast<sockaddr_in6*>(current->ai_addr);
serialized_addr.sin6_family = htons(addr.sin6_family);
serialized_addr.sin6_port = htons(addr.sin6_port);
serialized_addr.sin6_flowinfo = htonl(addr.sin6_flowinfo);
serialized_addr.sin6_scope_id = htonl(addr.sin6_scope_id);
std::memcpy(serialized_addr.sin6_addr, &addr.sin6_addr,
sizeof(SockAddrIn6::sin6_addr));
std::memcpy(header_ptr + header_size, &serialized_addr, sizeof(SockAddrIn6));
char addr_string_buf[64]{};
inet_ntop(AF_INET6, &addr.sin6_addr, addr_string_buf, std::size(addr_string_buf));
LOG_INFO(Service, "Resolved host '{}' to IPv6 address {}", host, addr_string_buf);
break;
}
default:
std::memcpy(header_ptr + header_size, current->ai_addr, addr_size);
break;
}
}
if (current->ai_canonname) {
std::memcpy(header_ptr + addr_size, current->ai_canonname, canonname_size);
} else {
*(header_ptr + header_size + addr_size) = 0;
data.push_back(0);
}
current = current->ai_next;
LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host,
Network::IPv4AddressToString(addrinfo.addr.ip));
}
// 4-byte sentinel value
data.push_back(0);
data.push_back(0);
data.push_back(0);
data.push_back(0);
data.resize(data.size() + 4, 0); // 4-byte sentinel value
return data;
}
static std::pair<u32, s32> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
struct Parameters {
static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
struct InputParameters {
u8 use_nsd_resolve;
u32 unknown;
u32 cancel_handle;
u64 process_id;
};
static_assert(sizeof(InputParameters) == 0x10);
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
const auto parameters = rp.PopRaw<InputParameters>();
LOG_WARNING(Service,
"called with ignored parameters: use_nsd_resolve={}, unknown={}, process_id={}",
parameters.use_nsd_resolve, parameters.unknown, parameters.process_id);
LOG_WARNING(
Service,
"called with ignored parameters: use_nsd_resolve={}, cancel_handle={}, process_id={}",
parameters.use_nsd_resolve, parameters.cancel_handle, parameters.process_id);
// TODO: If use_nsd_resolve is true, pass the name through NSD::Resolve
// before looking up.
const auto host_buffer = ctx.ReadBuffer(0);
const std::string host = Common::StringFromBuffer(host_buffer);
const auto service_buffer = ctx.ReadBuffer(1);
const std::string service = Common::StringFromBuffer(service_buffer);
addrinfo* addrinfo;
// Pass null for hints. Serialized hints are also passed in a buffer, but are ignored for now
s32 result_code = getaddrinfo(host.c_str(), service.c_str(), nullptr, &addrinfo);
u32 data_size = 0;
if (result_code == 0 && addrinfo != nullptr) {
const std::vector<u8>& data = SerializeAddrInfo(addrinfo, result_code, host);
data_size = static_cast<u32>(data.size());
freeaddrinfo(addrinfo);
ctx.WriteBuffer(data, 0);
std::optional<std::string> service = std::nullopt;
if (ctx.CanReadBuffer(1)) {
const std::span<const u8> service_buffer = ctx.ReadBuffer(1);
service = Common::StringFromBuffer(service_buffer);
}
return std::make_pair(data_size, result_code);
// Serialized hints are also passed in a buffer, but are ignored for now.
auto res = Network::GetAddressInfo(host, service);
if (!res.has_value()) {
return {0, Translate(res.error())};
}
const std::vector<u8> data = SerializeAddrInfo(res.value(), host);
const u32 data_size = static_cast<u32>(data.size());
ctx.WriteBuffer(data, 0);
return {data_size, GetAddrInfoError::SUCCESS};
}
void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx);
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
IPC::ResponseBuilder rb{ctx, 4};
struct OutputParameters {
Errno bsd_errno;
GetAddrInfoError gai_error;
u32 data_size;
};
static_assert(sizeof(OutputParameters) == 0xc);
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
rb.PushRaw(OutputParameters{
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
.gai_error = emu_gai_err,
.data_size = data_size,
});
}
void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) {
struct InputParameters {
GetAddrInfoError gai_errno;
};
IPC::RequestParser rp{ctx};
auto input = rp.PopRaw<InputParameters>();
const std::string result = Translate(input.gai_errno);
ctx.WriteBuffer(result);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(static_cast<s32>(AddrInfoErrorToNetDbError(result_code))); // NetDBErrorCode
rb.Push(result_code); // errno
rb.Push(data_size); // serialized size
}
void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
// Additional options are ignored
auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx);
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
IPC::ResponseBuilder rb{ctx, 5};
struct OutputParameters {
u32 data_size;
GetAddrInfoError gai_error;
NetDbError netdb_error;
Errno bsd_errno;
};
static_assert(sizeof(OutputParameters) == 0x10);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.Push(data_size); // serialized size
rb.Push(result_code); // errno
rb.Push(static_cast<s32>(AddrInfoErrorToNetDbError(result_code))); // NetDBErrorCode
rb.Push(0);
rb.PushRaw(OutputParameters{
.data_size = data_size,
.gai_error = emu_gai_err,
.netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
});
}
void SFDNSRES::ResolverSetOptionRequest(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<s32>(0); // bsd errno
}
} // namespace Service::Sockets

View File

@ -17,8 +17,12 @@ public:
~SFDNSRES() override;
private:
void GetHostByNameRequest(HLERequestContext& ctx);
void GetGaiStringErrorRequest(HLERequestContext& ctx);
void GetHostByNameRequestWithOptions(HLERequestContext& ctx);
void GetAddrInfoRequest(HLERequestContext& ctx);
void GetAddrInfoRequestWithOptions(HLERequestContext& ctx);
void ResolverSetOptionRequest(HLERequestContext& ctx);
};
} // namespace Service::Sockets

View File

@ -22,13 +22,35 @@ enum class Errno : u32 {
CONNRESET = 104,
NOTCONN = 107,
TIMEDOUT = 110,
INPROGRESS = 115,
};
enum class GetAddrInfoError : s32 {
SUCCESS = 0,
ADDRFAMILY = 1,
AGAIN = 2,
BADFLAGS = 3,
FAIL = 4,
FAMILY = 5,
MEMORY = 6,
NODATA = 7,
NONAME = 8,
SERVICE = 9,
SOCKTYPE = 10,
SYSTEM = 11,
BADHINTS = 12,
PROTOCOL = 13,
OVERFLOW_ = 14, // avoid name collision with Windows macro
OTHER = 15,
};
enum class Domain : u32 {
Unspecified = 0,
INET = 2,
};
enum class Type : u32 {
Unspecified = 0,
STREAM = 1,
DGRAM = 2,
RAW = 3,
@ -36,12 +58,16 @@ enum class Type : u32 {
};
enum class Protocol : u32 {
UNSPECIFIED = 0,
Unspecified = 0,
ICMP = 1,
TCP = 6,
UDP = 17,
};
enum class SocketLevel : u32 {
SOCKET = 0xffff, // i.e. SOL_SOCKET
};
enum class OptName : u32 {
REUSEADDR = 0x4,
KEEPALIVE = 0x8,
@ -51,6 +77,8 @@ enum class OptName : u32 {
RCVBUF = 0x1002,
SNDTIMEO = 0x1005,
RCVTIMEO = 0x1006,
ERROR_ = 0x1007, // avoid name collision with Windows macro
NOSIGPIPE = 0x800, // at least according to libnx
};
enum class ShutdownHow : s32 {
@ -80,6 +108,9 @@ enum class PollEvents : u16 {
Err = 1 << 3,
Hup = 1 << 4,
Nval = 1 << 5,
RdNorm = 1 << 6,
RdBand = 1 << 7,
WrBand = 1 << 8,
};
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);

View File

@ -29,6 +29,8 @@ Errno Translate(Network::Errno value) {
return Errno::TIMEDOUT;
case Network::Errno::CONNRESET:
return Errno::CONNRESET;
case Network::Errno::INPROGRESS:
return Errno::INPROGRESS;
default:
UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
return Errno::SUCCESS;
@ -39,8 +41,88 @@ std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
return {value.first, Translate(value.second)};
}
GetAddrInfoError Translate(Network::GetAddrInfoError error) {
switch (error) {
case Network::GetAddrInfoError::SUCCESS:
return GetAddrInfoError::SUCCESS;
case Network::GetAddrInfoError::ADDRFAMILY:
return GetAddrInfoError::ADDRFAMILY;
case Network::GetAddrInfoError::AGAIN:
return GetAddrInfoError::AGAIN;
case Network::GetAddrInfoError::BADFLAGS:
return GetAddrInfoError::BADFLAGS;
case Network::GetAddrInfoError::FAIL:
return GetAddrInfoError::FAIL;
case Network::GetAddrInfoError::FAMILY:
return GetAddrInfoError::FAMILY;
case Network::GetAddrInfoError::MEMORY:
return GetAddrInfoError::MEMORY;
case Network::GetAddrInfoError::NODATA:
return GetAddrInfoError::NODATA;
case Network::GetAddrInfoError::NONAME:
return GetAddrInfoError::NONAME;
case Network::GetAddrInfoError::SERVICE:
return GetAddrInfoError::SERVICE;
case Network::GetAddrInfoError::SOCKTYPE:
return GetAddrInfoError::SOCKTYPE;
case Network::GetAddrInfoError::SYSTEM:
return GetAddrInfoError::SYSTEM;
case Network::GetAddrInfoError::BADHINTS:
return GetAddrInfoError::BADHINTS;
case Network::GetAddrInfoError::PROTOCOL:
return GetAddrInfoError::PROTOCOL;
case Network::GetAddrInfoError::OVERFLOW_:
return GetAddrInfoError::OVERFLOW_;
case Network::GetAddrInfoError::OTHER:
return GetAddrInfoError::OTHER;
default:
UNIMPLEMENTED_MSG("Unimplemented GetAddrInfoError={}", error);
return GetAddrInfoError::OTHER;
}
}
const char* Translate(GetAddrInfoError error) {
// https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254
switch (error) {
case GetAddrInfoError::SUCCESS:
return "Success";
case GetAddrInfoError::ADDRFAMILY:
return "Address family for hostname not supported";
case GetAddrInfoError::AGAIN:
return "Temporary failure in name resolution";
case GetAddrInfoError::BADFLAGS:
return "Invalid value for ai_flags";
case GetAddrInfoError::FAIL:
return "Non-recoverable failure in name resolution";
case GetAddrInfoError::FAMILY:
return "ai_family not supported";
case GetAddrInfoError::MEMORY:
return "Memory allocation failure";
case GetAddrInfoError::NODATA:
return "No address associated with hostname";
case GetAddrInfoError::NONAME:
return "hostname nor servname provided, or not known";
case GetAddrInfoError::SERVICE:
return "servname not supported for ai_socktype";
case GetAddrInfoError::SOCKTYPE:
return "ai_socktype not supported";
case GetAddrInfoError::SYSTEM:
return "System error returned in errno";
case GetAddrInfoError::BADHINTS:
return "Invalid value for hints";
case GetAddrInfoError::PROTOCOL:
return "Resolved protocol is unknown";
case GetAddrInfoError::OVERFLOW_:
return "Argument buffer overflow";
default:
return "Unknown error";
}
}
Network::Domain Translate(Domain domain) {
switch (domain) {
case Domain::Unspecified:
return Network::Domain::Unspecified;
case Domain::INET:
return Network::Domain::INET;
default:
@ -51,6 +133,8 @@ Network::Domain Translate(Domain domain) {
Domain Translate(Network::Domain domain) {
switch (domain) {
case Network::Domain::Unspecified:
return Domain::Unspecified;
case Network::Domain::INET:
return Domain::INET;
default:
@ -61,39 +145,69 @@ Domain Translate(Network::Domain domain) {
Network::Type Translate(Type type) {
switch (type) {
case Type::Unspecified:
return Network::Type::Unspecified;
case Type::STREAM:
return Network::Type::STREAM;
case Type::DGRAM:
return Network::Type::DGRAM;
case Type::RAW:
return Network::Type::RAW;
case Type::SEQPACKET:
return Network::Type::SEQPACKET;
default:
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
return Network::Type{};
}
}
Network::Protocol Translate(Type type, Protocol protocol) {
Type Translate(Network::Type type) {
switch (type) {
case Network::Type::Unspecified:
return Type::Unspecified;
case Network::Type::STREAM:
return Type::STREAM;
case Network::Type::DGRAM:
return Type::DGRAM;
case Network::Type::RAW:
return Type::RAW;
case Network::Type::SEQPACKET:
return Type::SEQPACKET;
default:
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
return Type{};
}
}
Network::Protocol Translate(Protocol protocol) {
switch (protocol) {
case Protocol::UNSPECIFIED:
LOG_WARNING(Service, "Unspecified protocol, assuming protocol from type");
switch (type) {
case Type::DGRAM:
return Network::Protocol::UDP;
case Type::STREAM:
return Network::Protocol::TCP;
default:
return Network::Protocol::TCP;
}
case Protocol::Unspecified:
return Network::Protocol::Unspecified;
case Protocol::TCP:
return Network::Protocol::TCP;
case Protocol::UDP:
return Network::Protocol::UDP;
default:
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
return Network::Protocol::TCP;
return Network::Protocol::Unspecified;
}
}
Network::PollEvents TranslatePollEventsToHost(PollEvents flags) {
Protocol Translate(Network::Protocol protocol) {
switch (protocol) {
case Network::Protocol::Unspecified:
return Protocol::Unspecified;
case Network::Protocol::TCP:
return Protocol::TCP;
case Network::Protocol::UDP:
return Protocol::UDP;
default:
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
return Protocol::Unspecified;
}
}
Network::PollEvents Translate(PollEvents flags) {
Network::PollEvents result{};
const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) {
if (True(flags & from)) {
@ -107,12 +221,15 @@ Network::PollEvents TranslatePollEventsToHost(PollEvents flags) {
translate(PollEvents::Err, Network::PollEvents::Err);
translate(PollEvents::Hup, Network::PollEvents::Hup);
translate(PollEvents::Nval, Network::PollEvents::Nval);
translate(PollEvents::RdNorm, Network::PollEvents::RdNorm);
translate(PollEvents::RdBand, Network::PollEvents::RdBand);
translate(PollEvents::WrBand, Network::PollEvents::WrBand);
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
return result;
}
PollEvents TranslatePollEventsToGuest(Network::PollEvents flags) {
PollEvents Translate(Network::PollEvents flags) {
PollEvents result{};
const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) {
if (True(flags & from)) {
@ -127,13 +244,18 @@ PollEvents TranslatePollEventsToGuest(Network::PollEvents flags) {
translate(Network::PollEvents::Err, PollEvents::Err);
translate(Network::PollEvents::Hup, PollEvents::Hup);
translate(Network::PollEvents::Nval, PollEvents::Nval);
translate(Network::PollEvents::RdNorm, PollEvents::RdNorm);
translate(Network::PollEvents::RdBand, PollEvents::RdBand);
translate(Network::PollEvents::WrBand, PollEvents::WrBand);
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
return result;
}
Network::SockAddrIn Translate(SockAddrIn value) {
ASSERT(value.len == 0 || value.len == sizeof(value));
// Note: 6 is incorrect, but can be passed by homebrew (because libnx sets
// sin_len to 6 when deserializing getaddrinfo results).
ASSERT(value.len == 0 || value.len == sizeof(value) || value.len == 6);
return {
.family = Translate(static_cast<Domain>(value.family)),

View File

@ -17,6 +17,12 @@ Errno Translate(Network::Errno value);
/// Translate abstract return value errno pair to guest return value errno pair
std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
/// Translate abstract getaddrinfo error to guest getaddrinfo error
GetAddrInfoError Translate(Network::GetAddrInfoError value);
/// Translate guest error to string
const char* Translate(GetAddrInfoError value);
/// Translate guest domain to abstract domain
Network::Domain Translate(Domain domain);
@ -26,14 +32,20 @@ Domain Translate(Network::Domain domain);
/// Translate guest type to abstract type
Network::Type Translate(Type type);
/// Translate guest protocol to abstract protocol
Network::Protocol Translate(Type type, Protocol protocol);
/// Translate abstract type to guest type
Type Translate(Network::Type type);
/// Translate abstract poll event flags to guest poll event flags
Network::PollEvents TranslatePollEventsToHost(PollEvents flags);
/// Translate guest protocol to abstract protocol
Network::Protocol Translate(Protocol protocol);
/// Translate abstract protocol to guest protocol
Protocol Translate(Network::Protocol protocol);
/// Translate guest poll event flags to abstract poll event flags
PollEvents TranslatePollEventsToGuest(Network::PollEvents flags);
Network::PollEvents Translate(PollEvents flags);
/// Translate abstract poll event flags to guest poll event flags
PollEvents Translate(Network::PollEvents flags);
/// Translate guest socket address structure to abstract socket address structure
Network::SockAddrIn Translate(SockAddrIn value);

View File

@ -1,10 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/sockets/bsd.h"
#include "core/hle/service/ssl/ssl.h"
#include "core/hle/service/ssl/ssl_backend.h"
#include "core/internal_network/network.h"
#include "core/internal_network/sockets.h"
namespace Service::SSL {
@ -20,6 +28,18 @@ enum class ContextOption : u32 {
CrlImportDateCheckEnable = 1,
};
// This is nn::ssl::Connection::IoMode
enum class IoMode : u32 {
Blocking = 1,
NonBlocking = 2,
};
// This is nn::ssl::sf::OptionType
enum class OptionType : u32 {
DoNotCloseSocket = 0,
GetServerCertChain = 1,
};
// This is nn::ssl::sf::SslVersion
struct SslVersion {
union {
@ -34,35 +54,42 @@ struct SslVersion {
};
};
struct SslContextSharedData {
u32 connection_count = 0;
};
class ISslConnection final : public ServiceFramework<ISslConnection> {
public:
explicit ISslConnection(Core::System& system_, SslVersion version)
: ServiceFramework{system_, "ISslConnection"}, ssl_version{version} {
explicit ISslConnection(Core::System& system_in, SslVersion ssl_version_in,
std::shared_ptr<SslContextSharedData>& shared_data_in,
std::unique_ptr<SSLConnectionBackend>&& backend_in)
: ServiceFramework{system_in, "ISslConnection"}, ssl_version{ssl_version_in},
shared_data{shared_data_in}, backend{std::move(backend_in)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SetSocketDescriptor"},
{1, nullptr, "SetHostName"},
{2, nullptr, "SetVerifyOption"},
{3, nullptr, "SetIoMode"},
{0, &ISslConnection::SetSocketDescriptor, "SetSocketDescriptor"},
{1, &ISslConnection::SetHostName, "SetHostName"},
{2, &ISslConnection::SetVerifyOption, "SetVerifyOption"},
{3, &ISslConnection::SetIoMode, "SetIoMode"},
{4, nullptr, "GetSocketDescriptor"},
{5, nullptr, "GetHostName"},
{6, nullptr, "GetVerifyOption"},
{7, nullptr, "GetIoMode"},
{8, nullptr, "DoHandshake"},
{9, nullptr, "DoHandshakeGetServerCert"},
{10, nullptr, "Read"},
{11, nullptr, "Write"},
{12, nullptr, "Pending"},
{8, &ISslConnection::DoHandshake, "DoHandshake"},
{9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"},
{10, &ISslConnection::Read, "Read"},
{11, &ISslConnection::Write, "Write"},
{12, &ISslConnection::Pending, "Pending"},
{13, nullptr, "Peek"},
{14, nullptr, "Poll"},
{15, nullptr, "GetVerifyCertError"},
{16, nullptr, "GetNeededServerCertBufferSize"},
{17, nullptr, "SetSessionCacheMode"},
{17, &ISslConnection::SetSessionCacheMode, "SetSessionCacheMode"},
{18, nullptr, "GetSessionCacheMode"},
{19, nullptr, "FlushSessionCache"},
{20, nullptr, "SetRenegotiationMode"},
{21, nullptr, "GetRenegotiationMode"},
{22, nullptr, "SetOption"},
{22, &ISslConnection::SetOption, "SetOption"},
{23, nullptr, "GetOption"},
{24, nullptr, "GetVerifyCertErrors"},
{25, nullptr, "GetCipherInfo"},
@ -80,21 +107,299 @@ public:
// clang-format on
RegisterHandlers(functions);
shared_data->connection_count++;
}
~ISslConnection() {
shared_data->connection_count--;
if (fd_to_close.has_value()) {
const s32 fd = *fd_to_close;
if (!do_not_close_socket) {
LOG_ERROR(Service_SSL,
"do_not_close_socket was changed after setting socket; is this right?");
} else {
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
if (bsd) {
auto err = bsd->CloseImpl(fd);
if (err != Service::Sockets::Errno::SUCCESS) {
LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
}
}
}
}
}
private:
SslVersion ssl_version;
std::shared_ptr<SslContextSharedData> shared_data;
std::unique_ptr<SSLConnectionBackend> backend;
std::optional<int> fd_to_close;
bool do_not_close_socket = false;
bool get_server_cert_chain = false;
std::shared_ptr<Network::SocketBase> socket;
bool did_set_host_name = false;
bool did_handshake = false;
ResultVal<s32> SetSocketDescriptorImpl(s32 fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
s32 ret_fd;
// Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor
if (do_not_close_socket) {
auto res = bsd->DuplicateSocketImpl(fd);
if (!res.has_value()) {
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
return ResultInvalidSocket;
}
fd = *res;
fd_to_close = fd;
ret_fd = fd;
} else {
ret_fd = -1;
}
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
if (!sock.has_value()) {
LOG_ERROR(Service_SSL, "invalid socket fd {}", fd);
return ResultInvalidSocket;
}
socket = std::move(*sock);
backend->SetSocket(socket);
return ret_fd;
}
Result SetHostNameImpl(const std::string& hostname) {
LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
ASSERT(!did_handshake);
Result res = backend->SetHostName(hostname);
if (res == ResultSuccess) {
did_set_host_name = true;
}
return res;
}
Result SetVerifyOptionImpl(u32 option) {
ASSERT(!did_handshake);
LOG_WARNING(Service_SSL, "(STUBBED) called. option={}", option);
return ResultSuccess;
}
Result SetIoModeImpl(u32 input_mode) {
auto mode = static_cast<IoMode>(input_mode);
ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
ASSERT_OR_EXECUTE(socket, { return ResultNoSocket; });
const bool non_block = mode == IoMode::NonBlocking;
const Network::Errno error = socket->SetNonBlock(non_block);
if (error != Network::Errno::SUCCESS) {
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
}
return ResultSuccess;
}
Result SetSessionCacheModeImpl(u32 mode) {
ASSERT(!did_handshake);
LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
return ResultSuccess;
}
Result DoHandshakeImpl() {
ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
ASSERT_OR_EXECUTE_MSG(
did_set_host_name, { return ResultInternalError; },
"Expected SetHostName before DoHandshake");
Result res = backend->DoHandshake();
did_handshake = res.IsSuccess();
return res;
}
std::vector<u8> SerializeServerCerts(const std::vector<std::vector<u8>>& certs) {
struct Header {
u64 magic;
u32 count;
u32 pad;
};
struct EntryHeader {
u32 size;
u32 offset;
};
if (!get_server_cert_chain) {
// Just return the first one, unencoded.
ASSERT_OR_EXECUTE_MSG(
!certs.empty(), { return {}; }, "Should be at least one server cert");
return certs[0];
}
std::vector<u8> ret;
Header header{0x4E4D684374726543, static_cast<u32>(certs.size()), 0};
ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1));
size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader);
for (auto& cert : certs) {
EntryHeader entry_header{static_cast<u32>(cert.size()), static_cast<u32>(data_offset)};
data_offset += cert.size();
ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header),
reinterpret_cast<u8*>(&entry_header + 1));
}
for (auto& cert : certs) {
ret.insert(ret.end(), cert.begin(), cert.end());
}
return ret;
}
ResultVal<std::vector<u8>> ReadImpl(size_t size) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
std::vector<u8> res(size);
ResultVal<size_t> actual = backend->Read(res);
if (actual.Failed()) {
return actual.Code();
}
res.resize(*actual);
return res;
}
ResultVal<size_t> WriteImpl(std::span<const u8> data) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
return backend->Write(data);
}
ResultVal<s32> PendingImpl() {
LOG_WARNING(Service_SSL, "(STUBBED) called.");
return 0;
}
void SetSocketDescriptor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const ResultVal<s32> res = SetSocketDescriptorImpl(fd);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push<s32>(res.ValueOr(-1));
}
void SetHostName(HLERequestContext& ctx) {
const std::string hostname = Common::StringFromBuffer(ctx.ReadBuffer());
const Result res = SetHostNameImpl(hostname);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SetVerifyOption(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 option = rp.Pop<u32>();
const Result res = SetVerifyOptionImpl(option);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SetIoMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 mode = rp.Pop<u32>();
const Result res = SetIoModeImpl(mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void DoHandshake(HLERequestContext& ctx) {
const Result res = DoHandshakeImpl();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void DoHandshakeGetServerCert(HLERequestContext& ctx) {
struct OutputParameters {
u32 certs_size;
u32 certs_count;
};
static_assert(sizeof(OutputParameters) == 0x8);
const Result res = DoHandshakeImpl();
OutputParameters out{};
if (res == ResultSuccess) {
auto certs = backend->GetServerCerts();
if (certs.Succeeded()) {
const std::vector<u8> certs_buf = SerializeServerCerts(*certs);
ctx.WriteBuffer(certs_buf);
out.certs_count = static_cast<u32>(certs->size());
out.certs_size = static_cast<u32>(certs_buf.size());
}
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.PushRaw(out);
}
void Read(HLERequestContext& ctx) {
const ResultVal<std::vector<u8>> res = ReadImpl(ctx.GetWriteBufferSize());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
if (res.Succeeded()) {
rb.Push(static_cast<u32>(res->size()));
ctx.WriteBuffer(*res);
} else {
rb.Push(static_cast<u32>(0));
}
}
void Write(HLERequestContext& ctx) {
const ResultVal<size_t> res = WriteImpl(ctx.ReadBuffer());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push(static_cast<u32>(res.ValueOr(0)));
}
void Pending(HLERequestContext& ctx) {
const ResultVal<s32> res = PendingImpl();
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push<s32>(res.ValueOr(0));
}
void SetSessionCacheMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 mode = rp.Pop<u32>();
const Result res = SetSessionCacheModeImpl(mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SetOption(HLERequestContext& ctx) {
struct Parameters {
OptionType option;
s32 value;
};
static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
switch (parameters.option) {
case OptionType::DoNotCloseSocket:
do_not_close_socket = static_cast<bool>(parameters.value);
break;
case OptionType::GetServerCertChain:
get_server_cert_chain = static_cast<bool>(parameters.value);
break;
default:
LOG_WARNING(Service_SSL, "Unknown option={}, value={}", parameters.option,
parameters.value);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
class ISslContext final : public ServiceFramework<ISslContext> {
public:
explicit ISslContext(Core::System& system_, SslVersion version)
: ServiceFramework{system_, "ISslContext"}, ssl_version{version} {
: ServiceFramework{system_, "ISslContext"}, ssl_version{version},
shared_data{std::make_shared<SslContextSharedData>()} {
static const FunctionInfo functions[] = {
{0, &ISslContext::SetOption, "SetOption"},
{1, nullptr, "GetOption"},
{2, &ISslContext::CreateConnection, "CreateConnection"},
{3, nullptr, "GetConnectionCount"},
{3, &ISslContext::GetConnectionCount, "GetConnectionCount"},
{4, &ISslContext::ImportServerPki, "ImportServerPki"},
{5, &ISslContext::ImportClientPki, "ImportClientPki"},
{6, nullptr, "RemoveServerPki"},
@ -111,6 +416,7 @@ public:
private:
SslVersion ssl_version;
std::shared_ptr<SslContextSharedData> shared_data;
void SetOption(HLERequestContext& ctx) {
struct Parameters {
@ -130,11 +436,24 @@ private:
}
void CreateConnection(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
LOG_WARNING(Service_SSL, "called");
auto backend_res = CreateSSLConnectionBackend();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(backend_res.Code());
if (backend_res.Succeeded()) {
rb.PushIpcInterface<ISslConnection>(system, ssl_version, shared_data,
std::move(*backend_res));
}
}
void GetConnectionCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_SSL, "connection_count={}", shared_data->connection_count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISslConnection>(system, ssl_version);
rb.Push(shared_data->connection_count);
}
void ImportServerPki(HLERequestContext& ctx) {

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