Compare commits
80 Commits
android-2
...
android-19
Author | SHA1 | Date | |
---|---|---|---|
fcb741937e | |||
18000df5e9 | |||
bb0edb53ae | |||
099295d7c6 | |||
dad0d076ee | |||
3e3294e1c2 | |||
9f3f615e05 | |||
d144168442 | |||
3e4029b238 | |||
b1aed2c5b7 | |||
0ea138fb5b | |||
482c957f5d | |||
39edd2ff82 | |||
05bc024260 | |||
4bee333d84 | |||
efda6cc9ec | |||
8927f016e1 | |||
c0202da9ac | |||
7fc5ef68d2 | |||
014ca709c9 | |||
86bbfe3b1d | |||
1ab3bd5a5e | |||
c1e57ad358 | |||
4ecedc4991 | |||
71b3b2a2f0 | |||
80cd67ed7b | |||
3fded314f2 | |||
8f1d48fda6 | |||
16c238e4b9 | |||
e0fb1d3d17 | |||
5bbc3aef13 | |||
54f150b70a | |||
5593bed08a | |||
8750564bd2 | |||
2461c78e3f | |||
50fe45f1e4 | |||
4347dd26c6 | |||
474db2d8da | |||
a85ce8ea56 | |||
04868ab9da | |||
63a0a1f826 | |||
9e0d6f7d54 | |||
13755c0903 | |||
c3050c1b48 | |||
28598c9090 | |||
11cb4d88f0 | |||
4b870b28e8 | |||
ce7c418e0c | |||
169b198d08 | |||
833306bf5e | |||
90d76333da | |||
e32ce6cc69 | |||
190748546d | |||
79e289404b | |||
a6e467cd55 | |||
8a87a41f2d | |||
f02226283e | |||
82568412f6 | |||
1255196731 | |||
9ce5d39829 | |||
4540bcfaf7 | |||
aa882cdaa8 | |||
b417b8562e | |||
302a735135 | |||
f1cfd9c219 | |||
6f7cb69c94 | |||
644c3ce609 | |||
0ed1cb7266 | |||
0e191c2711 | |||
98685d48e3 | |||
d885dd5b64 | |||
b9f9d0a642 | |||
8b9c077826 | |||
cd4b8f037c | |||
ac939f08a4 | |||
42015de49b | |||
4a35569921 | |||
8905142f43 | |||
7cc428ddf6 | |||
8e703e08df |
@ -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
|
||||
|
@ -56,7 +56,6 @@ for i in package/*.exe; do
|
||||
x86_64-w64-mingw32-strip "${i}"
|
||||
done
|
||||
|
||||
pip3 install pefile
|
||||
python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/"
|
||||
|
||||
# copy FFmpeg libraries
|
||||
|
@ -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
2
.gitmodules
vendored
@ -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
|
||||
|
@ -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)
|
||||
@ -277,10 +289,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 +335,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}")
|
||||
|
@ -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
|
||||
|
6
externals/CMakeLists.txt
vendored
6
externals/CMakeLists.txt
vendored
@ -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)
|
||||
|
1
externals/VulkanMemoryAllocator
vendored
Submodule
1
externals/VulkanMemoryAllocator
vendored
Submodule
Submodule externals/VulkanMemoryAllocator added at 9b0fc3e7b0
171
externals/demangle/ItaniumDemangle.cpp
vendored
171
externals/demangle/ItaniumDemangle.cpp
vendored
@ -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;
|
||||
}
|
||||
}
|
||||
|
37
externals/demangle/llvm/Demangle/Demangle.h
vendored
37
externals/demangle/llvm/Demangle/Demangle.h
vendored
@ -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;
|
||||
|
@ -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
|
||||
|
3910
externals/demangle/llvm/Demangle/ItaniumDemangle.h
vendored
3910
externals/demangle/llvm/Demangle/ItaniumDemangle.h
vendored
File diff suppressed because it is too large
Load Diff
96
externals/demangle/llvm/Demangle/ItaniumNodes.def
vendored
Normal file
96
externals/demangle/llvm/Demangle/ItaniumNodes.def
vendored
Normal 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
|
32
externals/demangle/llvm/Demangle/StringView.h
vendored
32
externals/demangle/llvm/Demangle/StringView.h
vendored
@ -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
|
||||
|
39
externals/demangle/llvm/Demangle/StringViewExtras.h
vendored
Normal file
39
externals/demangle/llvm/Demangle/StringViewExtras.h
vendored
Normal 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
|
208
externals/demangle/llvm/Demangle/Utility.h
vendored
208
externals/demangle/llvm/Demangle/Utility.h
vendored
@ -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
|
||||
|
1
externals/vma/VulkanMemoryAllocator
vendored
1
externals/vma/VulkanMemoryAllocator
vendored
Submodule externals/vma/VulkanMemoryAllocator deleted from 0aa3989b8f
@ -22,7 +22,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
android:label="@string/app_name_suffixed"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:allowBackup="true"
|
||||
android:hasFragileUserData="true"
|
||||
android:hasFragileUserData="false"
|
||||
android:supportsRtl="true"
|
||||
android:isGame="true"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
|
@ -12,6 +12,7 @@ import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
|
||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||
import org.yuzu.yuzu_emu.model.HomeSetting
|
||||
|
||||
class HomeSettingAdapter(private val activity: AppCompatActivity, var options: List<HomeSetting>) :
|
||||
@ -34,7 +35,14 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
|
||||
|
||||
override fun onClick(view: View) {
|
||||
val holder = view.tag as HomeOptionViewHolder
|
||||
holder.option.onClick.invoke()
|
||||
if (holder.option.isEnabled.invoke()) {
|
||||
holder.option.onClick.invoke()
|
||||
} else {
|
||||
MessageDialogFragment.newInstance(
|
||||
holder.option.disabledTitleId,
|
||||
holder.option.disabledMessageId
|
||||
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
|
||||
@ -65,6 +73,12 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
|
||||
R.drawable.premium_background
|
||||
)
|
||||
}
|
||||
|
||||
if (!option.isEnabled.invoke()) {
|
||||
binding.optionTitle.alpha = 0.5f
|
||||
binding.optionDescription.alpha = 0.5f
|
||||
binding.optionIcon.alpha = 0.5f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,102 +73,113 @@ class HomeSettingsFragment : Fragment() {
|
||||
HomeSetting(
|
||||
R.string.advanced_settings,
|
||||
R.string.settings_description,
|
||||
R.drawable.ic_settings
|
||||
) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
|
||||
R.drawable.ic_settings,
|
||||
{ SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.open_user_folder,
|
||||
R.string.open_user_folder_description,
|
||||
R.drawable.ic_folder_open
|
||||
) { openFileManager() }
|
||||
R.drawable.ic_folder_open,
|
||||
{ openFileManager() }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.preferences_theme,
|
||||
R.string.theme_and_color_description,
|
||||
R.drawable.ic_palette
|
||||
) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
|
||||
)
|
||||
|
||||
if (GpuDriverHelper.supportsCustomDriverLoading()) {
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_gpu_driver,
|
||||
R.string.install_gpu_driver_description,
|
||||
R.drawable.ic_exit
|
||||
) { driverInstaller() }
|
||||
R.drawable.ic_palette,
|
||||
{ SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
|
||||
)
|
||||
}
|
||||
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_gpu_driver,
|
||||
R.string.install_gpu_driver_description,
|
||||
R.drawable.ic_exit,
|
||||
{ driverInstaller() },
|
||||
{ GpuDriverHelper.supportsCustomDriverLoading() },
|
||||
R.string.custom_driver_not_supported,
|
||||
R.string.custom_driver_not_supported_description
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_amiibo_keys,
|
||||
R.string.install_amiibo_keys_description,
|
||||
R.drawable.ic_nfc
|
||||
) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
|
||||
R.drawable.ic_nfc,
|
||||
{ mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_game_content,
|
||||
R.string.install_game_content_description,
|
||||
R.drawable.ic_system_update_alt
|
||||
) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
|
||||
R.drawable.ic_system_update_alt,
|
||||
{ mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.select_games_folder,
|
||||
R.string.select_games_folder_description,
|
||||
R.drawable.ic_add
|
||||
) {
|
||||
mainActivity.getGamesDirectory.launch(
|
||||
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
|
||||
)
|
||||
}
|
||||
R.drawable.ic_add,
|
||||
{
|
||||
mainActivity.getGamesDirectory.launch(
|
||||
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.manage_save_data,
|
||||
R.string.import_export_saves_description,
|
||||
R.drawable.ic_save
|
||||
) {
|
||||
ImportExportSavesFragment().show(
|
||||
parentFragmentManager,
|
||||
ImportExportSavesFragment.TAG
|
||||
)
|
||||
}
|
||||
R.drawable.ic_save,
|
||||
{
|
||||
ImportExportSavesFragment().show(
|
||||
parentFragmentManager,
|
||||
ImportExportSavesFragment.TAG
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_prod_keys,
|
||||
R.string.install_prod_keys_description,
|
||||
R.drawable.ic_unlock
|
||||
) { mainActivity.getProdKey.launch(arrayOf("*/*")) }
|
||||
R.drawable.ic_unlock,
|
||||
{ mainActivity.getProdKey.launch(arrayOf("*/*")) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_firmware,
|
||||
R.string.install_firmware_description,
|
||||
R.drawable.ic_firmware
|
||||
) { mainActivity.getFirmware.launch(arrayOf("application/zip")) }
|
||||
R.drawable.ic_firmware,
|
||||
{ mainActivity.getFirmware.launch(arrayOf("application/zip")) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.share_log,
|
||||
R.string.share_log_description,
|
||||
R.drawable.ic_log
|
||||
) { shareLog() }
|
||||
R.drawable.ic_log,
|
||||
{ shareLog() }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.about,
|
||||
R.string.about_description,
|
||||
R.drawable.ic_info_outline
|
||||
) {
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
parentFragmentManager.primaryNavigationFragment?.findNavController()
|
||||
?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
|
||||
}
|
||||
R.drawable.ic_info_outline,
|
||||
{
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
parentFragmentManager.primaryNavigationFragment?.findNavController()
|
||||
?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -178,12 +189,13 @@ class HomeSettingsFragment : Fragment() {
|
||||
HomeSetting(
|
||||
R.string.get_early_access,
|
||||
R.string.get_early_access_description,
|
||||
R.drawable.ic_diamond
|
||||
) {
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
parentFragmentManager.primaryNavigationFragment?.findNavController()
|
||||
?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment)
|
||||
}
|
||||
R.drawable.ic_diamond,
|
||||
{
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
parentFragmentManager.primaryNavigationFragment?.findNavController()
|
||||
?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -7,5 +7,8 @@ data class HomeSetting(
|
||||
val titleId: Int,
|
||||
val descriptionId: Int,
|
||||
val iconId: Int,
|
||||
val onClick: () -> Unit
|
||||
val onClick: () -> Unit,
|
||||
val isEnabled: () -> Boolean = { true },
|
||||
val disabledTitleId: Int = 0,
|
||||
val disabledMessageId: Int = 0
|
||||
)
|
||||
|
@ -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;
|
||||
|
@ -113,6 +113,8 @@
|
||||
<string name="install_game_content_success_install">%1$d installed successfully</string>
|
||||
<string name="install_game_content_success_overwrite">%1$d overwritten successfully</string>
|
||||
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
|
||||
<string name="custom_driver_not_supported">Custom drivers not supported</string>
|
||||
<string name="custom_driver_not_supported_description">Custom driver loading isn\'t currently supported for this device.\nCheck this option again in the future to see if support was added!</string>
|
||||
|
||||
<!-- About screen strings -->
|
||||
<string name="gaia_is_not_real">Gaia isn\'t real</string>
|
||||
@ -230,7 +232,7 @@
|
||||
|
||||
<!-- ROM loading errors -->
|
||||
<string name="loader_error_encrypted">Your ROM is encrypted</string>
|
||||
<string name="loader_error_encrypted_roms_description"><![CDATA[Please follow the guides to redump your <a href="https://yuzu-emu.org/help/quickstart/#dumping-cartridge-games">game cartidges</a> or <a href="https://yuzu-emu.org/help/quickstart/#dumping-installed-titles-eshop">installed titles</a>.]]></string>
|
||||
<string name="loader_error_encrypted_roms_description"><![CDATA[Please follow the guides to redump your <a href="https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards">game cartidges</a> or <a href="https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop">installed titles</a>.]]></string>
|
||||
<string name="loader_error_encrypted_keys_description"><![CDATA[Please ensure your <a href="https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys">prod.keys</a> file is installed so that games can be decrypted.]]></string>
|
||||
<string name="loader_error_video_core">An error occurred initializing the video core</string>
|
||||
<string name="loader_error_video_core_description">This is usually caused by an incompatible GPU driver. Installing a custom GPU driver may resolve this problem.</string>
|
||||
|
@ -92,9 +92,9 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
|
||||
if (type == Sink::StreamType::In) {
|
||||
stream->AppendBuffer(new_buffer, tmp_samples);
|
||||
} else {
|
||||
system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(),
|
||||
buffer.size);
|
||||
stream->AppendBuffer(new_buffer, tmp_samples);
|
||||
Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
|
||||
system.ApplicationMemory(), buffer.samples, buffer.size / sizeof(s16));
|
||||
stream->AppendBuffer(new_buffer, samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ constexpr std::array<u8, 3> PitchBySrcQuality = {4, 8, 4};
|
||||
template <typename T>
|
||||
static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const DecodeArg& req) {
|
||||
std::array<T, TempBufferSize> tmp_samples{};
|
||||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||
|
||||
@ -49,19 +48,18 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const VAddr source{req.buffer +
|
||||
(((req.start_offset + req.offset) * channel_count) * sizeof(T))};
|
||||
const u64 size{channel_count * samples_to_decode};
|
||||
const u64 size_bytes{size * sizeof(T)};
|
||||
|
||||
memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes);
|
||||
|
||||
Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
|
||||
memory, source, size);
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
|
||||
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
|
||||
std::numeric_limits<s16>::max())};
|
||||
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
|
||||
}
|
||||
} else {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
out_buffer[i] = tmp_samples[i * channel_count + req.target_channel];
|
||||
out_buffer[i] = samples[i * channel_count + req.target_channel];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@ -74,16 +72,17 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
}
|
||||
|
||||
const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
|
||||
memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T));
|
||||
Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
|
||||
memory, source, samples_to_decode);
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
|
||||
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
|
||||
std::numeric_limits<s16>::max())};
|
||||
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
|
||||
}
|
||||
} else {
|
||||
std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16));
|
||||
std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -101,7 +100,6 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
*/
|
||||
static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const DecodeArg& req) {
|
||||
std::array<u8, TempBufferSize> wavebuffer{};
|
||||
constexpr u32 SamplesPerFrame{14};
|
||||
constexpr u32 NibblesPerFrame{16};
|
||||
|
||||
@ -139,7 +137,8 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
}
|
||||
|
||||
const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
|
||||
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size);
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> wavebuffer(
|
||||
memory, req.buffer + position_in_frame / 2, size);
|
||||
|
||||
auto context{req.adpcm_context};
|
||||
auto header{context->header};
|
||||
|
@ -21,23 +21,13 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
|
||||
}
|
||||
|
||||
AuxInfo::AuxInfoDsp info{};
|
||||
auto info_ptr{&info};
|
||||
bool host_safe{(aux_info & Core::Memory::YUZU_PAGEMASK) <=
|
||||
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp))};
|
||||
memory.ReadBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp));
|
||||
|
||||
if (host_safe) [[likely]] {
|
||||
info_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(aux_info);
|
||||
} else {
|
||||
memory.ReadBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
|
||||
}
|
||||
info.read_offset = 0;
|
||||
info.write_offset = 0;
|
||||
info.total_sample_count = 0;
|
||||
|
||||
info_ptr->read_offset = 0;
|
||||
info_ptr->write_offset = 0;
|
||||
info_ptr->total_sample_count = 0;
|
||||
|
||||
if (!host_safe) [[unlikely]] {
|
||||
memory.WriteBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
|
||||
}
|
||||
memory.WriteBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,17 +76,9 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
|
||||
}
|
||||
|
||||
AuxInfo::AuxInfoDsp send_info{};
|
||||
auto send_ptr = &send_info;
|
||||
bool host_safe = (send_info_ & Core::Memory::YUZU_PAGEMASK) <=
|
||||
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
|
||||
memory.ReadBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
|
||||
|
||||
if (host_safe) [[likely]] {
|
||||
send_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(send_info_);
|
||||
} else {
|
||||
memory.ReadBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
|
||||
}
|
||||
|
||||
u32 target_write_offset{send_ptr->write_offset + write_offset};
|
||||
u32 target_write_offset{send_info.write_offset + write_offset};
|
||||
if (target_write_offset > count_max) {
|
||||
return 0;
|
||||
}
|
||||
@ -105,15 +87,9 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
|
||||
u32 read_pos{0};
|
||||
while (write_count > 0) {
|
||||
u32 to_write{std::min(count_max - target_write_offset, write_count)};
|
||||
const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
|
||||
bool write_safe{(write_addr & Core::Memory::YUZU_PAGEMASK) <=
|
||||
(Core::Memory::YUZU_PAGESIZE - (write_addr + to_write * sizeof(s32)))};
|
||||
if (write_safe) [[likely]] {
|
||||
auto ptr = memory.GetPointer(write_addr);
|
||||
std::memcpy(ptr, &input[read_pos], to_write * sizeof(s32));
|
||||
} else {
|
||||
memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
|
||||
&input[read_pos], to_write * sizeof(s32));
|
||||
if (to_write > 0) {
|
||||
const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
|
||||
memory.WriteBlockUnsafe(write_addr, &input[read_pos], to_write * sizeof(s32));
|
||||
}
|
||||
target_write_offset = (target_write_offset + to_write) % count_max;
|
||||
write_count -= to_write;
|
||||
@ -121,13 +97,10 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
|
||||
}
|
||||
|
||||
if (update_count) {
|
||||
send_ptr->write_offset = (send_ptr->write_offset + update_count) % count_max;
|
||||
}
|
||||
|
||||
if (!host_safe) [[unlikely]] {
|
||||
memory.WriteBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
|
||||
send_info.write_offset = (send_info.write_offset + update_count) % count_max;
|
||||
}
|
||||
|
||||
memory.WriteBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
|
||||
return write_count_;
|
||||
}
|
||||
|
||||
@ -174,17 +147,9 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
|
||||
}
|
||||
|
||||
AuxInfo::AuxInfoDsp return_info{};
|
||||
auto return_ptr = &return_info;
|
||||
bool host_safe = (return_info_ & Core::Memory::YUZU_PAGEMASK) <=
|
||||
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
|
||||
memory.ReadBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
|
||||
|
||||
if (host_safe) [[likely]] {
|
||||
return_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(return_info_);
|
||||
} else {
|
||||
memory.ReadBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
|
||||
}
|
||||
|
||||
u32 target_read_offset{return_ptr->read_offset + read_offset};
|
||||
u32 target_read_offset{return_info.read_offset + read_offset};
|
||||
if (target_read_offset > count_max) {
|
||||
return 0;
|
||||
}
|
||||
@ -193,15 +158,9 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
|
||||
u32 write_pos{0};
|
||||
while (read_count > 0) {
|
||||
u32 to_read{std::min(count_max - target_read_offset, read_count)};
|
||||
const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
|
||||
bool read_safe{(read_addr & Core::Memory::YUZU_PAGEMASK) <=
|
||||
(Core::Memory::YUZU_PAGESIZE - (read_addr + to_read * sizeof(s32)))};
|
||||
if (read_safe) [[likely]] {
|
||||
auto ptr = memory.GetPointer(read_addr);
|
||||
std::memcpy(&output[write_pos], ptr, to_read * sizeof(s32));
|
||||
} else {
|
||||
memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
|
||||
&output[write_pos], to_read * sizeof(s32));
|
||||
if (to_read > 0) {
|
||||
const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
|
||||
memory.ReadBlockUnsafe(read_addr, &output[write_pos], to_read * sizeof(s32));
|
||||
}
|
||||
target_read_offset = (target_read_offset + to_read) % count_max;
|
||||
read_count -= to_read;
|
||||
@ -209,13 +168,10 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
|
||||
}
|
||||
|
||||
if (update_count) {
|
||||
return_ptr->read_offset = (return_ptr->read_offset + update_count) % count_max;
|
||||
}
|
||||
|
||||
if (!host_safe) [[unlikely]] {
|
||||
memory.WriteBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
|
||||
return_info.read_offset = (return_info.read_offset + update_count) % count_max;
|
||||
}
|
||||
|
||||
memory.WriteBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
|
||||
return read_count_;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -66,6 +66,7 @@ void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page
|
||||
<< (address_space_width_in_bits - page_size_in_bits)};
|
||||
pointers.resize(num_page_table_entries);
|
||||
backing_addr.resize(num_page_table_entries);
|
||||
blocks.resize(num_page_table_entries);
|
||||
current_address_space_width_in_bits = address_space_width_in_bits;
|
||||
page_size = 1ULL << page_size_in_bits;
|
||||
}
|
||||
|
@ -122,6 +122,7 @@ struct PageTable {
|
||||
* corresponding attribute element is of type `Memory`.
|
||||
*/
|
||||
VirtualBuffer<PageInfo> pointers;
|
||||
VirtualBuffer<u64> blocks;
|
||||
|
||||
VirtualBuffer<u64> backing_addr;
|
||||
|
||||
|
@ -40,8 +40,21 @@ public:
|
||||
~ScratchBuffer() = default;
|
||||
ScratchBuffer(const ScratchBuffer&) = delete;
|
||||
ScratchBuffer& operator=(const ScratchBuffer&) = delete;
|
||||
ScratchBuffer(ScratchBuffer&&) = default;
|
||||
ScratchBuffer& operator=(ScratchBuffer&&) = default;
|
||||
|
||||
ScratchBuffer(ScratchBuffer&& other) noexcept {
|
||||
swap(other);
|
||||
other.last_requested_size = 0;
|
||||
other.buffer_capacity = 0;
|
||||
other.buffer.reset();
|
||||
}
|
||||
|
||||
ScratchBuffer& operator=(ScratchBuffer&& other) noexcept {
|
||||
swap(other);
|
||||
other.last_requested_size = 0;
|
||||
other.buffer_capacity = 0;
|
||||
other.buffer.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// This will only grow the buffer's capacity if size is greater than the current capacity.
|
||||
/// The previously held data will remain intact.
|
||||
|
@ -26,9 +26,10 @@ std::string GetTimeZoneString() {
|
||||
|
||||
std::string location_name;
|
||||
if (time_zone_index == 0) { // Auto
|
||||
#if __cpp_lib_chrono >= 201907L
|
||||
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
|
||||
#if __cpp_lib_chrono >= 201907L && !defined(MINGW)
|
||||
// Disabled for MinGW -- tzdb always returns Etc/UTC
|
||||
try {
|
||||
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
|
||||
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
|
||||
std::string_view current_zone_name = current_zone->name();
|
||||
location_name = current_zone_name;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -285,6 +285,7 @@ add_library(core STATIC
|
||||
hle/kernel/kernel.cpp
|
||||
hle/kernel/kernel.h
|
||||
hle/kernel/memory_types.h
|
||||
hle/kernel/message_buffer.h
|
||||
hle/kernel/physical_core.cpp
|
||||
hle/kernel/physical_core.h
|
||||
hle/kernel/physical_memory.h
|
||||
@ -722,6 +723,7 @@ add_library(core STATIC
|
||||
hle/service/spl/spl_types.h
|
||||
hle/service/ssl/ssl.cpp
|
||||
hle/service/ssl/ssl.h
|
||||
hle/service/ssl/ssl_backend.h
|
||||
hle/service/time/clock_types.h
|
||||
hle/service/time/ephemeral_network_system_clock_context_writer.h
|
||||
hle/service/time/ephemeral_network_system_clock_core.h
|
||||
@ -863,6 +865,23 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_link_libraries(core PRIVATE dynarmic::dynarmic)
|
||||
endif()
|
||||
|
||||
if(ENABLE_OPENSSL)
|
||||
target_sources(core PRIVATE
|
||||
hle/service/ssl/ssl_backend_openssl.cpp)
|
||||
target_link_libraries(core PRIVATE OpenSSL::SSL)
|
||||
elseif (APPLE)
|
||||
target_sources(core PRIVATE
|
||||
hle/service/ssl/ssl_backend_securetransport.cpp)
|
||||
target_link_libraries(core PRIVATE "-framework Security")
|
||||
elseif (WIN32)
|
||||
target_sources(core PRIVATE
|
||||
hle/service/ssl/ssl_backend_schannel.cpp)
|
||||
target_link_libraries(core PRIVATE crypt32 secur32)
|
||||
else()
|
||||
target_sources(core PRIVATE
|
||||
hle/service/ssl/ssl_backend_none.cpp)
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
target_precompile_headers(core PRIVATE precompiled_headers.h)
|
||||
endif()
|
||||
|
@ -185,7 +185,7 @@ void ARM_Interface::Run() {
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
|
||||
if (!True(hr & HaltReason::InstructionBreakpoint)) {
|
||||
if (!True(hr & HaltReason::PrefetchAbort)) {
|
||||
RewindBreakpointInstruction();
|
||||
}
|
||||
if (system.DebuggerEnabled()) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -70,7 +70,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
||||
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
||||
if (is_multicore) {
|
||||
timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
|
||||
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,7 +255,6 @@ void CoreTiming::ThreadLoop() {
|
||||
#ifdef _WIN32
|
||||
while (!paused && !event.IsSet() && wait_time > 0) {
|
||||
wait_time = *next_time - GetGlobalTimeNs().count();
|
||||
|
||||
if (wait_time >= timer_resolution_ns) {
|
||||
Common::Windows::SleepForOneTick();
|
||||
} else {
|
||||
|
@ -163,7 +163,7 @@ private:
|
||||
Common::Event pause_event{};
|
||||
std::mutex basic_lock;
|
||||
std::mutex advance_lock;
|
||||
std::unique_ptr<std::thread> timer_thread;
|
||||
std::unique_ptr<std::jthread> timer_thread;
|
||||
std::atomic<bool> paused{};
|
||||
std::atomic<bool> paused_set{};
|
||||
std::atomic<bool> wait_set{};
|
||||
|
@ -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"
|
||||
|
@ -57,11 +57,34 @@ struct NCASectionHeaderBlock {
|
||||
};
|
||||
static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
|
||||
|
||||
struct NCABucketInfo {
|
||||
u64 table_offset;
|
||||
u64 table_size;
|
||||
std::array<u8, 0x10> table_header;
|
||||
};
|
||||
static_assert(sizeof(NCABucketInfo) == 0x20, "NCABucketInfo has incorrect size.");
|
||||
|
||||
struct NCASparseInfo {
|
||||
NCABucketInfo bucket;
|
||||
u64 physical_offset;
|
||||
u16 generation;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x6);
|
||||
};
|
||||
static_assert(sizeof(NCASparseInfo) == 0x30, "NCASparseInfo has incorrect size.");
|
||||
|
||||
struct NCACompressionInfo {
|
||||
NCABucketInfo bucket;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x8);
|
||||
};
|
||||
static_assert(sizeof(NCACompressionInfo) == 0x28, "NCACompressionInfo has incorrect size.");
|
||||
|
||||
struct NCASectionRaw {
|
||||
NCASectionHeaderBlock header;
|
||||
std::array<u8, 0x138> block_data;
|
||||
std::array<u8, 0x8> section_ctr;
|
||||
INSERT_PADDING_BYTES_NOINIT(0xB8);
|
||||
NCASparseInfo sparse_info;
|
||||
NCACompressionInfo compression_info;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x60);
|
||||
};
|
||||
static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size.");
|
||||
|
||||
@ -225,6 +248,20 @@ bool NCA::ReadSections(const std::vector<NCASectionHeader>& sections, u64 bktr_b
|
||||
for (std::size_t i = 0; i < sections.size(); ++i) {
|
||||
const auto& section = sections[i];
|
||||
|
||||
if (section.raw.sparse_info.bucket.table_offset != 0 &&
|
||||
section.raw.sparse_info.bucket.table_size != 0) {
|
||||
LOG_ERROR(Loader, "Sparse NCAs are not supported.");
|
||||
status = Loader::ResultStatus::ErrorSparseNCA;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (section.raw.compression_info.bucket.table_offset != 0 &&
|
||||
section.raw.compression_info.bucket.table_size != 0) {
|
||||
LOG_ERROR(Loader, "Compressed NCAs are not supported.");
|
||||
status = Loader::ResultStatus::ErrorCompressedNCA;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
|
||||
if (!ReadRomFSSection(section, header.section_tables[i], bktr_base_ivfc_offset)) {
|
||||
return false;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -20,12 +20,132 @@
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_thread_queue.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/message_buffer.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
namespace {
|
||||
|
||||
template <bool MoveHandleAllowed>
|
||||
Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, KThread& src_thread,
|
||||
MessageBuffer& dst_msg, const MessageBuffer& src_msg,
|
||||
MessageBuffer::SpecialHeader& src_special_header) {
|
||||
// Copy the special header to the destination.
|
||||
s32 offset = dst_msg.Set(src_special_header);
|
||||
|
||||
// Copy the process ID.
|
||||
if (src_special_header.GetHasProcessId()) {
|
||||
offset = dst_msg.SetProcessId(offset, src_process.GetProcessId());
|
||||
}
|
||||
|
||||
// Prepare to process handles.
|
||||
auto& dst_handle_table = dst_process.GetHandleTable();
|
||||
auto& src_handle_table = src_process.GetHandleTable();
|
||||
Result result = ResultSuccess;
|
||||
|
||||
// Process copy handles.
|
||||
for (auto i = 0; i < src_special_header.GetCopyHandleCount(); ++i) {
|
||||
// Get the handles.
|
||||
const Handle src_handle = src_msg.GetHandle(offset);
|
||||
Handle dst_handle = Svc::InvalidHandle;
|
||||
|
||||
// If we're in a success state, try to move the handle to the new table.
|
||||
if (R_SUCCEEDED(result) && src_handle != Svc::InvalidHandle) {
|
||||
KScopedAutoObject obj =
|
||||
src_handle_table.GetObjectForIpc(src_handle, std::addressof(src_thread));
|
||||
if (obj.IsNotNull()) {
|
||||
Result add_result =
|
||||
dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe());
|
||||
if (R_FAILED(add_result)) {
|
||||
result = add_result;
|
||||
dst_handle = Svc::InvalidHandle;
|
||||
}
|
||||
} else {
|
||||
result = ResultInvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the handle.
|
||||
offset = dst_msg.SetHandle(offset, dst_handle);
|
||||
}
|
||||
|
||||
// Process move handles.
|
||||
if constexpr (MoveHandleAllowed) {
|
||||
for (auto i = 0; i < src_special_header.GetMoveHandleCount(); ++i) {
|
||||
// Get the handles.
|
||||
const Handle src_handle = src_msg.GetHandle(offset);
|
||||
Handle dst_handle = Svc::InvalidHandle;
|
||||
|
||||
// Whether or not we've succeeded, we need to remove the handles from the source table.
|
||||
if (src_handle != Svc::InvalidHandle) {
|
||||
if (R_SUCCEEDED(result)) {
|
||||
KScopedAutoObject obj =
|
||||
src_handle_table.GetObjectForIpcWithoutPseudoHandle(src_handle);
|
||||
if (obj.IsNotNull()) {
|
||||
Result add_result = dst_handle_table.Add(std::addressof(dst_handle),
|
||||
obj.GetPointerUnsafe());
|
||||
|
||||
src_handle_table.Remove(src_handle);
|
||||
|
||||
if (R_FAILED(add_result)) {
|
||||
result = add_result;
|
||||
dst_handle = Svc::InvalidHandle;
|
||||
}
|
||||
} else {
|
||||
result = ResultInvalidHandle;
|
||||
}
|
||||
} else {
|
||||
src_handle_table.Remove(src_handle);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the handle.
|
||||
offset = dst_msg.SetHandle(offset, dst_handle);
|
||||
}
|
||||
}
|
||||
|
||||
R_RETURN(result);
|
||||
}
|
||||
|
||||
void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) {
|
||||
// Parse the message.
|
||||
const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
|
||||
const MessageBuffer::MessageHeader dst_header(dst_msg);
|
||||
const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header);
|
||||
|
||||
// Check that the size is big enough.
|
||||
if (MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) > dst_buffer_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the special header.
|
||||
int offset = dst_msg.Set(dst_special_header);
|
||||
|
||||
// Clear the process id, if needed.
|
||||
if (dst_special_header.GetHasProcessId()) {
|
||||
offset = dst_msg.SetProcessId(offset, 0);
|
||||
}
|
||||
|
||||
// Clear handles, as relevant.
|
||||
auto& dst_handle_table = dst_process.GetHandleTable();
|
||||
for (auto i = 0;
|
||||
i < (dst_special_header.GetCopyHandleCount() + dst_special_header.GetMoveHandleCount());
|
||||
++i) {
|
||||
const Handle handle = dst_msg.GetHandle(offset);
|
||||
|
||||
if (handle != Svc::InvalidHandle) {
|
||||
dst_handle_table.Remove(handle);
|
||||
}
|
||||
|
||||
offset = dst_msg.SetHandle(offset, Svc::InvalidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
|
||||
|
||||
KServerSession::KServerSession(KernelCore& kernel)
|
||||
@ -223,12 +343,27 @@ Result KServerSession::SendReply(bool is_hle) {
|
||||
// the reply has already been written in this case.
|
||||
} else {
|
||||
Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
|
||||
KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
|
||||
KThread* server_thread = GetCurrentThreadPointer(m_kernel);
|
||||
KProcess& src_process = *client_thread->GetOwnerProcess();
|
||||
KProcess& dst_process = *server_thread->GetOwnerProcess();
|
||||
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
||||
|
||||
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
|
||||
auto* dst_msg_buffer = memory.GetPointer(client_message);
|
||||
auto* src_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
|
||||
auto* dst_msg_buffer = memory.GetPointer<u32>(client_message);
|
||||
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
||||
|
||||
// Translate special header ad-hoc.
|
||||
MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
|
||||
MessageBuffer::MessageHeader src_header(src_msg);
|
||||
MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
|
||||
if (src_header.GetHasSpecialHeader()) {
|
||||
MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
|
||||
result = ProcessMessageSpecialData<true>(dst_process, src_process, *server_thread,
|
||||
dst_msg, src_msg, src_special_header);
|
||||
if (R_FAILED(result)) {
|
||||
CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = ResultSessionClosed;
|
||||
@ -330,12 +465,28 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
|
||||
->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
|
||||
cmd_buf);
|
||||
} else {
|
||||
KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
|
||||
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
||||
KThread* server_thread = GetCurrentThreadPointer(m_kernel);
|
||||
KProcess& src_process = *client_thread->GetOwnerProcess();
|
||||
KProcess& dst_process = *server_thread->GetOwnerProcess();
|
||||
UNIMPLEMENTED_IF(client_thread->GetOwnerProcess() != server_thread->GetOwnerProcess());
|
||||
|
||||
auto* src_msg_buffer = memory.GetPointer(client_message);
|
||||
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
|
||||
auto* src_msg_buffer = memory.GetPointer<u32>(client_message);
|
||||
auto* dst_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
|
||||
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
||||
|
||||
// Translate special header ad-hoc.
|
||||
// TODO: fix this mess
|
||||
MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
|
||||
MessageBuffer::MessageHeader src_header(src_msg);
|
||||
MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
|
||||
if (src_header.GetHasSpecialHeader()) {
|
||||
MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
|
||||
Result res = ProcessMessageSpecialData<false>(dst_process, src_process, *client_thread,
|
||||
dst_msg, src_msg, src_special_header);
|
||||
if (R_FAILED(res)) {
|
||||
CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We succeeded.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
612
src/core/hle/kernel/message_buffer.h
Normal file
612
src/core/hle/kernel/message_buffer.h
Normal file
@ -0,0 +1,612 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/bit_field.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
constexpr inline size_t MessageBufferSize = 0x100;
|
||||
|
||||
class MessageBuffer {
|
||||
public:
|
||||
class MessageHeader {
|
||||
private:
|
||||
static constexpr inline u64 NullTag = 0;
|
||||
|
||||
public:
|
||||
enum class ReceiveListCountType : u32 {
|
||||
None = 0,
|
||||
ToMessageBuffer = 1,
|
||||
ToSingleBuffer = 2,
|
||||
|
||||
CountOffset = 2,
|
||||
CountMax = 13,
|
||||
};
|
||||
|
||||
private:
|
||||
union {
|
||||
std::array<u32, 2> raw;
|
||||
|
||||
struct {
|
||||
// Define fields for the first header word.
|
||||
union {
|
||||
BitField<0, 16, u16> tag;
|
||||
BitField<16, 4, u32> pointer_count;
|
||||
BitField<20, 4, u32> send_count;
|
||||
BitField<24, 4, u32> receive_count;
|
||||
BitField<28, 4, u32> exchange_count;
|
||||
};
|
||||
|
||||
// Define fields for the second header word.
|
||||
union {
|
||||
BitField<0, 10, u32> raw_count;
|
||||
BitField<10, 4, ReceiveListCountType> receive_list_count;
|
||||
BitField<14, 6, u32> reserved0;
|
||||
BitField<20, 11, u32> receive_list_offset;
|
||||
BitField<31, 1, u32> has_special_header;
|
||||
};
|
||||
};
|
||||
} m_header;
|
||||
|
||||
public:
|
||||
constexpr MessageHeader() : m_header{} {}
|
||||
|
||||
constexpr MessageHeader(u16 tag, bool special, s32 ptr, s32 send, s32 recv, s32 exch,
|
||||
s32 raw, ReceiveListCountType recv_list)
|
||||
: m_header{} {
|
||||
m_header.raw[0] = 0;
|
||||
m_header.raw[1] = 0;
|
||||
|
||||
m_header.tag.Assign(tag);
|
||||
m_header.pointer_count.Assign(ptr);
|
||||
m_header.send_count.Assign(send);
|
||||
m_header.receive_count.Assign(recv);
|
||||
m_header.exchange_count.Assign(exch);
|
||||
|
||||
m_header.raw_count.Assign(raw);
|
||||
m_header.receive_list_count.Assign(recv_list);
|
||||
m_header.has_special_header.Assign(special);
|
||||
}
|
||||
|
||||
explicit MessageHeader(const MessageBuffer& buf) : m_header{} {
|
||||
buf.Get(0, m_header.raw.data(), 2);
|
||||
}
|
||||
|
||||
explicit MessageHeader(const u32* msg) : m_header{{msg[0], msg[1]}} {}
|
||||
|
||||
constexpr u16 GetTag() const {
|
||||
return m_header.tag;
|
||||
}
|
||||
|
||||
constexpr s32 GetPointerCount() const {
|
||||
return m_header.pointer_count;
|
||||
}
|
||||
|
||||
constexpr s32 GetSendCount() const {
|
||||
return m_header.send_count;
|
||||
}
|
||||
|
||||
constexpr s32 GetReceiveCount() const {
|
||||
return m_header.receive_count;
|
||||
}
|
||||
|
||||
constexpr s32 GetExchangeCount() const {
|
||||
return m_header.exchange_count;
|
||||
}
|
||||
|
||||
constexpr s32 GetMapAliasCount() const {
|
||||
return this->GetSendCount() + this->GetReceiveCount() + this->GetExchangeCount();
|
||||
}
|
||||
|
||||
constexpr s32 GetRawCount() const {
|
||||
return m_header.raw_count;
|
||||
}
|
||||
|
||||
constexpr ReceiveListCountType GetReceiveListCount() const {
|
||||
return m_header.receive_list_count;
|
||||
}
|
||||
|
||||
constexpr s32 GetReceiveListOffset() const {
|
||||
return m_header.receive_list_offset;
|
||||
}
|
||||
|
||||
constexpr bool GetHasSpecialHeader() const {
|
||||
return m_header.has_special_header.Value() != 0;
|
||||
}
|
||||
|
||||
constexpr void SetReceiveListCount(ReceiveListCountType recv_list) {
|
||||
m_header.receive_list_count.Assign(recv_list);
|
||||
}
|
||||
|
||||
constexpr const u32* GetData() const {
|
||||
return m_header.raw.data();
|
||||
}
|
||||
|
||||
static constexpr size_t GetDataSize() {
|
||||
return sizeof(m_header);
|
||||
}
|
||||
};
|
||||
|
||||
class SpecialHeader {
|
||||
private:
|
||||
union {
|
||||
std::array<u32, 1> raw;
|
||||
|
||||
// Define fields for the header word.
|
||||
BitField<0, 1, u32> has_process_id;
|
||||
BitField<1, 4, u32> copy_handle_count;
|
||||
BitField<5, 4, u32> move_handle_count;
|
||||
} m_header;
|
||||
bool m_has_header;
|
||||
|
||||
public:
|
||||
constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move)
|
||||
: m_header{}, m_has_header(true) {
|
||||
m_header.has_process_id.Assign(pid);
|
||||
m_header.copy_handle_count.Assign(copy);
|
||||
m_header.move_handle_count.Assign(move);
|
||||
}
|
||||
|
||||
constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move, bool _has_header)
|
||||
: m_header{}, m_has_header(_has_header) {
|
||||
m_header.has_process_id.Assign(pid);
|
||||
m_header.copy_handle_count.Assign(copy);
|
||||
m_header.move_handle_count.Assign(move);
|
||||
}
|
||||
|
||||
explicit SpecialHeader(const MessageBuffer& buf, const MessageHeader& hdr)
|
||||
: m_header{}, m_has_header(hdr.GetHasSpecialHeader()) {
|
||||
if (m_has_header) {
|
||||
buf.Get(static_cast<s32>(MessageHeader::GetDataSize() / sizeof(u32)),
|
||||
m_header.raw.data(), sizeof(m_header) / sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool GetHasProcessId() const {
|
||||
return m_header.has_process_id.Value() != 0;
|
||||
}
|
||||
|
||||
constexpr s32 GetCopyHandleCount() const {
|
||||
return m_header.copy_handle_count;
|
||||
}
|
||||
|
||||
constexpr s32 GetMoveHandleCount() const {
|
||||
return m_header.move_handle_count;
|
||||
}
|
||||
|
||||
constexpr const u32* GetHeader() const {
|
||||
return m_header.raw.data();
|
||||
}
|
||||
|
||||
constexpr size_t GetHeaderSize() const {
|
||||
if (m_has_header) {
|
||||
return sizeof(m_header);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t GetDataSize() const {
|
||||
if (m_has_header) {
|
||||
return (this->GetHasProcessId() ? sizeof(u64) : 0) +
|
||||
(this->GetCopyHandleCount() * sizeof(Handle)) +
|
||||
(this->GetMoveHandleCount() * sizeof(Handle));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MapAliasDescriptor {
|
||||
public:
|
||||
enum class Attribute : u32 {
|
||||
Ipc = 0,
|
||||
NonSecureIpc = 1,
|
||||
NonDeviceIpc = 3,
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr u32 SizeLowCount = 32;
|
||||
static constexpr u32 SizeHighCount = 4;
|
||||
static constexpr u32 AddressLowCount = 32;
|
||||
static constexpr u32 AddressMidCount = 4;
|
||||
|
||||
constexpr u32 GetAddressMid(u64 address) {
|
||||
return static_cast<u32>(address >> AddressLowCount) & ((1U << AddressMidCount) - 1);
|
||||
}
|
||||
|
||||
constexpr u32 GetAddressHigh(u64 address) {
|
||||
return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
std::array<u32, 3> raw;
|
||||
|
||||
struct {
|
||||
// Define fields for the first two words.
|
||||
u32 size_low;
|
||||
u32 address_low;
|
||||
|
||||
// Define fields for the packed descriptor word.
|
||||
union {
|
||||
BitField<0, 2, Attribute> attributes;
|
||||
BitField<2, 3, u32> address_high;
|
||||
BitField<5, 19, u32> reserved;
|
||||
BitField<24, 4, u32> size_high;
|
||||
BitField<28, 4, u32> address_mid;
|
||||
};
|
||||
};
|
||||
} m_data;
|
||||
|
||||
public:
|
||||
constexpr MapAliasDescriptor() : m_data{} {}
|
||||
|
||||
MapAliasDescriptor(const void* buffer, size_t _size, Attribute attr = Attribute::Ipc)
|
||||
: m_data{} {
|
||||
const u64 address = reinterpret_cast<u64>(buffer);
|
||||
const u64 size = static_cast<u64>(_size);
|
||||
m_data.size_low = static_cast<u32>(size);
|
||||
m_data.address_low = static_cast<u32>(address);
|
||||
m_data.attributes.Assign(attr);
|
||||
m_data.address_mid.Assign(GetAddressMid(address));
|
||||
m_data.size_high.Assign(static_cast<u32>(size >> SizeLowCount));
|
||||
m_data.address_high.Assign(GetAddressHigh(address));
|
||||
}
|
||||
|
||||
MapAliasDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
|
||||
buf.Get(index, m_data.raw.data(), 3);
|
||||
}
|
||||
|
||||
constexpr uintptr_t GetAddress() const {
|
||||
return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
|
||||
<< AddressLowCount) |
|
||||
m_data.address_low;
|
||||
}
|
||||
|
||||
constexpr uintptr_t GetSize() const {
|
||||
return (static_cast<u64>(m_data.size_high) << SizeLowCount) | m_data.size_low;
|
||||
}
|
||||
|
||||
constexpr Attribute GetAttribute() const {
|
||||
return m_data.attributes;
|
||||
}
|
||||
|
||||
constexpr const u32* GetData() const {
|
||||
return m_data.raw.data();
|
||||
}
|
||||
|
||||
static constexpr size_t GetDataSize() {
|
||||
return sizeof(m_data);
|
||||
}
|
||||
};
|
||||
|
||||
class PointerDescriptor {
|
||||
private:
|
||||
static constexpr u32 AddressLowCount = 32;
|
||||
static constexpr u32 AddressMidCount = 4;
|
||||
|
||||
constexpr u32 GetAddressMid(u64 address) {
|
||||
return static_cast<u32>(address >> AddressLowCount) & ((1u << AddressMidCount) - 1);
|
||||
}
|
||||
|
||||
constexpr u32 GetAddressHigh(u64 address) {
|
||||
return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
std::array<u32, 2> raw;
|
||||
|
||||
struct {
|
||||
// Define fields for the packed descriptor word.
|
||||
union {
|
||||
BitField<0, 4, u32> index;
|
||||
BitField<4, 2, u32> reserved0;
|
||||
BitField<6, 3, u32> address_high;
|
||||
BitField<9, 3, u32> reserved1;
|
||||
BitField<12, 4, u32> address_mid;
|
||||
BitField<16, 16, u32> size;
|
||||
};
|
||||
|
||||
// Define fields for the second word.
|
||||
u32 address_low;
|
||||
};
|
||||
} m_data;
|
||||
|
||||
public:
|
||||
constexpr PointerDescriptor() : m_data{} {}
|
||||
|
||||
PointerDescriptor(const void* buffer, size_t size, s32 index) : m_data{} {
|
||||
const u64 address = reinterpret_cast<u64>(buffer);
|
||||
|
||||
m_data.index.Assign(index);
|
||||
m_data.address_high.Assign(GetAddressHigh(address));
|
||||
m_data.address_mid.Assign(GetAddressMid(address));
|
||||
m_data.size.Assign(static_cast<u32>(size));
|
||||
|
||||
m_data.address_low = static_cast<u32>(address);
|
||||
}
|
||||
|
||||
PointerDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
|
||||
buf.Get(index, m_data.raw.data(), 2);
|
||||
}
|
||||
|
||||
constexpr s32 GetIndex() const {
|
||||
return m_data.index;
|
||||
}
|
||||
|
||||
constexpr uintptr_t GetAddress() const {
|
||||
return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
|
||||
<< AddressLowCount) |
|
||||
m_data.address_low;
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return m_data.size;
|
||||
}
|
||||
|
||||
constexpr const u32* GetData() const {
|
||||
return m_data.raw.data();
|
||||
}
|
||||
|
||||
static constexpr size_t GetDataSize() {
|
||||
return sizeof(m_data);
|
||||
}
|
||||
};
|
||||
|
||||
class ReceiveListEntry {
|
||||
private:
|
||||
static constexpr u32 AddressLowCount = 32;
|
||||
|
||||
constexpr u32 GetAddressHigh(u64 address) {
|
||||
return static_cast<u32>(address >> (AddressLowCount));
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
std::array<u32, 2> raw;
|
||||
|
||||
struct {
|
||||
// Define fields for the first word.
|
||||
u32 address_low;
|
||||
|
||||
// Define fields for the packed descriptor word.
|
||||
union {
|
||||
BitField<0, 7, u32> address_high;
|
||||
BitField<7, 9, u32> reserved;
|
||||
BitField<16, 16, u32> size;
|
||||
};
|
||||
};
|
||||
} m_data;
|
||||
|
||||
public:
|
||||
constexpr ReceiveListEntry() : m_data{} {}
|
||||
|
||||
ReceiveListEntry(const void* buffer, size_t size) : m_data{} {
|
||||
const u64 address = reinterpret_cast<u64>(buffer);
|
||||
|
||||
m_data.address_low = static_cast<u32>(address);
|
||||
|
||||
m_data.address_high.Assign(GetAddressHigh(address));
|
||||
m_data.size.Assign(static_cast<u32>(size));
|
||||
}
|
||||
|
||||
ReceiveListEntry(u32 a, u32 b) : m_data{{a, b}} {}
|
||||
|
||||
constexpr uintptr_t GetAddress() const {
|
||||
return (static_cast<u64>(m_data.address_high) << AddressLowCount) | m_data.address_low;
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return m_data.size;
|
||||
}
|
||||
|
||||
constexpr const u32* GetData() const {
|
||||
return m_data.raw.data();
|
||||
}
|
||||
|
||||
static constexpr size_t GetDataSize() {
|
||||
return sizeof(m_data);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
u32* m_buffer;
|
||||
size_t m_size;
|
||||
|
||||
public:
|
||||
constexpr MessageBuffer(u32* b, size_t sz) : m_buffer(b), m_size(sz) {}
|
||||
constexpr explicit MessageBuffer(u32* b) : m_buffer(b), m_size(MessageBufferSize) {}
|
||||
|
||||
constexpr void* GetBufferForDebug() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
constexpr size_t GetBufferSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void Get(s32 index, u32* dst, size_t count) const {
|
||||
// Ensure that this doesn't get re-ordered.
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
|
||||
// Get the words.
|
||||
static_assert(sizeof(*dst) == sizeof(*m_buffer));
|
||||
|
||||
memcpy(dst, m_buffer + index, count * sizeof(*dst));
|
||||
}
|
||||
|
||||
s32 Set(s32 index, u32* src, size_t count) const {
|
||||
// Ensure that this doesn't get re-ordered.
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
|
||||
// Set the words.
|
||||
memcpy(m_buffer + index, src, count * sizeof(*src));
|
||||
|
||||
// Ensure that this doesn't get re-ordered.
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
|
||||
return static_cast<s32>(index + count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetRaw(s32 index) const {
|
||||
return *reinterpret_cast<const T*>(m_buffer + index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
s32 SetRaw(s32 index, const T& val) const {
|
||||
*reinterpret_cast<const T*>(m_buffer + index) = val;
|
||||
return index + (Common::AlignUp(sizeof(val), sizeof(*m_buffer)) / sizeof(*m_buffer));
|
||||
}
|
||||
|
||||
void GetRawArray(s32 index, void* dst, size_t len) const {
|
||||
memcpy(dst, m_buffer + index, len);
|
||||
}
|
||||
|
||||
void SetRawArray(s32 index, const void* src, size_t len) const {
|
||||
memcpy(m_buffer + index, src, len);
|
||||
}
|
||||
|
||||
void SetNull() const {
|
||||
this->Set(MessageHeader());
|
||||
}
|
||||
|
||||
s32 Set(const MessageHeader& hdr) const {
|
||||
memcpy(m_buffer, hdr.GetData(), hdr.GetDataSize());
|
||||
return static_cast<s32>(hdr.GetDataSize() / sizeof(*m_buffer));
|
||||
}
|
||||
|
||||
s32 Set(const SpecialHeader& spc) const {
|
||||
const s32 index = static_cast<s32>(MessageHeader::GetDataSize() / sizeof(*m_buffer));
|
||||
memcpy(m_buffer + index, spc.GetHeader(), spc.GetHeaderSize());
|
||||
return static_cast<s32>(index + (spc.GetHeaderSize() / sizeof(*m_buffer)));
|
||||
}
|
||||
|
||||
s32 SetHandle(s32 index, const Handle& hnd) const {
|
||||
memcpy(m_buffer + index, std::addressof(hnd), sizeof(hnd));
|
||||
return static_cast<s32>(index + (sizeof(hnd) / sizeof(*m_buffer)));
|
||||
}
|
||||
|
||||
s32 SetProcessId(s32 index, const u64 pid) const {
|
||||
memcpy(m_buffer + index, std::addressof(pid), sizeof(pid));
|
||||
return static_cast<s32>(index + (sizeof(pid) / sizeof(*m_buffer)));
|
||||
}
|
||||
|
||||
s32 Set(s32 index, const MapAliasDescriptor& desc) const {
|
||||
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
|
||||
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
|
||||
}
|
||||
|
||||
s32 Set(s32 index, const PointerDescriptor& desc) const {
|
||||
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
|
||||
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
|
||||
}
|
||||
|
||||
s32 Set(s32 index, const ReceiveListEntry& desc) const {
|
||||
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
|
||||
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
|
||||
}
|
||||
|
||||
s32 Set(s32 index, const u32 val) const {
|
||||
memcpy(m_buffer + index, std::addressof(val), sizeof(val));
|
||||
return static_cast<s32>(index + (sizeof(val) / sizeof(*m_buffer)));
|
||||
}
|
||||
|
||||
Result GetAsyncResult() const {
|
||||
MessageHeader hdr(m_buffer);
|
||||
MessageHeader null{};
|
||||
if (memcmp(hdr.GetData(), null.GetData(), MessageHeader::GetDataSize()) != 0) [[unlikely]] {
|
||||
R_SUCCEED();
|
||||
}
|
||||
return Result(m_buffer[MessageHeader::GetDataSize() / sizeof(*m_buffer)]);
|
||||
}
|
||||
|
||||
void SetAsyncResult(Result res) const {
|
||||
const s32 index = this->Set(MessageHeader());
|
||||
const auto value = res.raw;
|
||||
memcpy(m_buffer + index, std::addressof(value), sizeof(value));
|
||||
}
|
||||
|
||||
u32 Get32(s32 index) const {
|
||||
return m_buffer[index];
|
||||
}
|
||||
|
||||
u64 Get64(s32 index) const {
|
||||
u64 value;
|
||||
memcpy(std::addressof(value), m_buffer + index, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
u64 GetProcessId(s32 index) const {
|
||||
return this->Get64(index);
|
||||
}
|
||||
|
||||
Handle GetHandle(s32 index) const {
|
||||
static_assert(sizeof(Handle) == sizeof(*m_buffer));
|
||||
return Handle(m_buffer[index]);
|
||||
}
|
||||
|
||||
static constexpr s32 GetSpecialDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
|
||||
return static_cast<s32>((MessageHeader::GetDataSize() / sizeof(u32)) +
|
||||
(spc.GetHeaderSize() / sizeof(u32)));
|
||||
}
|
||||
|
||||
static constexpr s32 GetPointerDescriptorIndex(const MessageHeader& hdr,
|
||||
const SpecialHeader& spc) {
|
||||
return static_cast<s32>(GetSpecialDataIndex(hdr, spc) + (spc.GetDataSize() / sizeof(u32)));
|
||||
}
|
||||
|
||||
static constexpr s32 GetMapAliasDescriptorIndex(const MessageHeader& hdr,
|
||||
const SpecialHeader& spc) {
|
||||
return GetPointerDescriptorIndex(hdr, spc) +
|
||||
static_cast<s32>(hdr.GetPointerCount() * PointerDescriptor::GetDataSize() /
|
||||
sizeof(u32));
|
||||
}
|
||||
|
||||
static constexpr s32 GetRawDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
|
||||
return GetMapAliasDescriptorIndex(hdr, spc) +
|
||||
static_cast<s32>(hdr.GetMapAliasCount() * MapAliasDescriptor::GetDataSize() /
|
||||
sizeof(u32));
|
||||
}
|
||||
|
||||
static constexpr s32 GetReceiveListIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
|
||||
if (const s32 recv_list_index = hdr.GetReceiveListOffset()) {
|
||||
return recv_list_index;
|
||||
} else {
|
||||
return GetRawDataIndex(hdr, spc) + hdr.GetRawCount();
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr size_t GetMessageBufferSize(const MessageHeader& hdr,
|
||||
const SpecialHeader& spc) {
|
||||
// Get the size of the plain message.
|
||||
size_t msg_size = GetReceiveListIndex(hdr, spc) * sizeof(u32);
|
||||
|
||||
// Add the size of the receive list.
|
||||
const auto count = hdr.GetReceiveListCount();
|
||||
switch (count) {
|
||||
case MessageHeader::ReceiveListCountType::None:
|
||||
break;
|
||||
case MessageHeader::ReceiveListCountType::ToMessageBuffer:
|
||||
break;
|
||||
case MessageHeader::ReceiveListCountType::ToSingleBuffer:
|
||||
msg_size += ReceiveListEntry::GetDataSize();
|
||||
break;
|
||||
default:
|
||||
msg_size += (static_cast<s32>(count) -
|
||||
static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
|
||||
ReceiveListEntry::GetDataSize();
|
||||
break;
|
||||
}
|
||||
|
||||
return msg_size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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>(
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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>(
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -329,8 +329,22 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
|
||||
}
|
||||
|
||||
std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
|
||||
static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a;
|
||||
static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x;
|
||||
static thread_local std::array read_buffer_a{
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
};
|
||||
static thread_local std::array read_buffer_data_a{
|
||||
Common::ScratchBuffer<u8>(),
|
||||
Common::ScratchBuffer<u8>(),
|
||||
};
|
||||
static thread_local std::array read_buffer_x{
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
|
||||
};
|
||||
static thread_local std::array read_buffer_data_x{
|
||||
Common::ScratchBuffer<u8>(),
|
||||
Common::ScratchBuffer<u8>(),
|
||||
};
|
||||
|
||||
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
|
||||
BufferDescriptorA()[buffer_index].Size()};
|
||||
@ -339,19 +353,17 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
|
||||
BufferDescriptorA().size() > buffer_index, { return {}; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
auto& read_buffer = read_buffer_a[buffer_index];
|
||||
read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(),
|
||||
read_buffer.size());
|
||||
return read_buffer;
|
||||
return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(),
|
||||
BufferDescriptorA()[buffer_index].Size(),
|
||||
&read_buffer_data_a[buffer_index]);
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorX().size() > buffer_index, { return {}; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
auto& read_buffer = read_buffer_x[buffer_index];
|
||||
read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(),
|
||||
read_buffer.size());
|
||||
return read_buffer;
|
||||
return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(),
|
||||
BufferDescriptorX()[buffer_index].Size(),
|
||||
&read_buffer_data_x[buffer_index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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{};
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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"},
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)),
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
45
src/core/hle/service/ssl/ssl_backend.h
Normal file
45
src/core/hle/service/ssl/ssl_backend.h
Normal file
@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Network {
|
||||
class SocketBase;
|
||||
}
|
||||
|
||||
namespace Service::SSL {
|
||||
|
||||
constexpr Result ResultNoSocket{ErrorModule::SSLSrv, 103};
|
||||
constexpr Result ResultInvalidSocket{ErrorModule::SSLSrv, 106};
|
||||
constexpr Result ResultTimeout{ErrorModule::SSLSrv, 205};
|
||||
constexpr Result ResultInternalError{ErrorModule::SSLSrv, 999}; // made up
|
||||
|
||||
// ResultWouldBlock is returned from Read and Write, and oddly, DoHandshake,
|
||||
// with no way in the latter case to distinguish whether the client should poll
|
||||
// for read or write. The one official client I've seen handles this by always
|
||||
// polling for read (with a timeout).
|
||||
constexpr Result ResultWouldBlock{ErrorModule::SSLSrv, 204};
|
||||
|
||||
class SSLConnectionBackend {
|
||||
public:
|
||||
virtual ~SSLConnectionBackend() {}
|
||||
virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
|
||||
virtual Result SetHostName(const std::string& hostname) = 0;
|
||||
virtual Result DoHandshake() = 0;
|
||||
virtual ResultVal<size_t> Read(std::span<u8> data) = 0;
|
||||
virtual ResultVal<size_t> Write(std::span<const u8> data) = 0;
|
||||
virtual ResultVal<std::vector<std::vector<u8>>> GetServerCerts() = 0;
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend();
|
||||
|
||||
} // namespace Service::SSL
|
16
src/core/hle/service/ssl/ssl_backend_none.cpp
Normal file
16
src/core/hle/service/ssl/ssl_backend_none.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/hle/service/ssl/ssl_backend.h"
|
||||
|
||||
namespace Service::SSL {
|
||||
|
||||
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
|
||||
LOG_ERROR(Service_SSL,
|
||||
"Can't create SSL connection because no SSL backend is available on this platform");
|
||||
return ResultInternalError;
|
||||
}
|
||||
|
||||
} // namespace Service::SSL
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user