summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/core.cpp1
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/crypto/partition_data_manager.cpp1
-rw-r--r--src/core/file_sys/bis_factory.cpp1
-rw-r--r--src/core/file_sys/bis_factory.h3
-rw-r--r--src/core/file_sys/card_image.cpp5
-rw-r--r--src/core/file_sys/card_image.h7
-rw-r--r--src/core/file_sys/content_archive.cpp5
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp1
-rw-r--r--src/core/file_sys/control_metadata.h2
-rw-r--r--src/core/file_sys/kernel_executable.cpp3
-rw-r--r--src/core/file_sys/kernel_executable.h9
-rw-r--r--src/core/file_sys/nca_metadata.cpp1
-rw-r--r--src/core/file_sys/nca_metadata.h2
-rw-r--r--src/core/file_sys/partition_filesystem.cpp8
-rw-r--r--src/core/file_sys/partition_filesystem.h8
-rw-r--r--src/core/file_sys/patch_manager.cpp3
-rw-r--r--src/core/file_sys/patch_manager.h6
-rw-r--r--src/core/file_sys/program_metadata.cpp1
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/romfs.h1
-rw-r--r--src/core/file_sys/sdmc_factory.cpp2
-rw-r--r--src/core/file_sys/sdmc_factory.h2
-rw-r--r--src/core/file_sys/submission_package.cpp2
-rw-r--r--src/core/file_sys/submission_package.h6
-rw-r--r--src/core/file_sys/xts_archive.cpp10
-rw-r--r--src/core/file_sys/xts_archive.h10
-rw-r--r--src/core/frontend/framebuffer_layout.h1
-rw-r--r--src/core/hle/kernel/kernel.cpp3
-rw-r--r--src/core/hle/kernel/scheduler.cpp8
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/npad.h1
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp12
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp12
-rw-r--r--src/core/hle/service/nifm/nifm.cpp13
-rw-r--r--src/core/hle/service/ns/ns.cpp1
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sockets/blocking_worker.h162
-rw-r--r--src/core/hle/service/sockets/bsd.cpp809
-rw-r--r--src/core/hle/service/sockets/bsd.h150
-rw-r--r--src/core/hle/service/sockets/sockets.cpp6
-rw-r--r--src/core/hle/service/sockets/sockets.h85
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp165
-rw-r--r--src/core/hle/service/sockets/sockets_translate.h48
-rw-r--r--src/core/settings.h12
49 files changed, 1523 insertions, 109 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c85c9485f..b96ca9374 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -491,6 +491,7 @@ add_library(core STATIC
491 hle/service/sm/controller.h 491 hle/service/sm/controller.h
492 hle/service/sm/sm.cpp 492 hle/service/sm/sm.cpp
493 hle/service/sm/sm.h 493 hle/service/sm/sm.h
494 hle/service/sockets/blocking_worker.h
494 hle/service/sockets/bsd.cpp 495 hle/service/sockets/bsd.cpp
495 hle/service/sockets/bsd.h 496 hle/service/sockets/bsd.h
496 hle/service/sockets/ethc.cpp 497 hle/service/sockets/ethc.cpp
@@ -501,6 +502,8 @@ add_library(core STATIC
501 hle/service/sockets/sfdnsres.h 502 hle/service/sockets/sfdnsres.h
502 hle/service/sockets/sockets.cpp 503 hle/service/sockets/sockets.cpp
503 hle/service/sockets/sockets.h 504 hle/service/sockets/sockets.h
505 hle/service/sockets/sockets_translate.cpp
506 hle/service/sockets/sockets_translate.h
504 hle/service/spl/csrng.cpp 507 hle/service/spl/csrng.cpp
505 hle/service/spl/csrng.h 508 hle/service/spl/csrng.h
506 hle/service/spl/module.cpp 509 hle/service/spl/module.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index c2c0eec0b..df81e8e2c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -188,7 +188,6 @@ struct System::Impl {
188 if (!gpu_core) { 188 if (!gpu_core) {
189 return ResultStatus::ErrorVideoCore; 189 return ResultStatus::ErrorVideoCore;
190 } 190 }
191 gpu_core->Renderer().Rasterizer().SetupDirtyFlags();
192 191
193 is_powered_on = true; 192 is_powered_on = true;
194 exit_lock = false; 193 exit_lock = false;
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index ef0bae556..688b99eba 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -328,7 +328,7 @@ void CpuManager::RunThread(std::size_t core) {
328 system.RegisterCoreThread(core); 328 system.RegisterCoreThread(core);
329 std::string name; 329 std::string name;
330 if (is_multicore) { 330 if (is_multicore) {
331 name = "yuzu:CoreCPUThread_" + std::to_string(core); 331 name = "yuzu:CPUCore_" + std::to_string(core);
332 } else { 332 } else {
333 name = "yuzu:CPUThread"; 333 name = "yuzu:CPUThread";
334 } 334 }
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index 46136d04a..5f1c86a09 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -26,6 +26,7 @@
26#include "core/file_sys/vfs.h" 26#include "core/file_sys/vfs.h"
27#include "core/file_sys/vfs_offset.h" 27#include "core/file_sys/vfs_offset.h"
28#include "core/file_sys/vfs_vector.h" 28#include "core/file_sys/vfs_vector.h"
29#include "core/loader/loader.h"
29 30
30using Common::AsArray; 31using Common::AsArray;
31 32
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 9ffda2e14..e04a54c3c 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -8,7 +8,6 @@
8#include "core/file_sys/bis_factory.h" 8#include "core/file_sys/bis_factory.h"
9#include "core/file_sys/mode.h" 9#include "core/file_sys/mode.h"
10#include "core/file_sys/registered_cache.h" 10#include "core/file_sys/registered_cache.h"
11#include "core/settings.h"
12 11
13namespace FileSys { 12namespace FileSys {
14 13
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 8f0451c98..438d3f8d8 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -6,7 +6,8 @@
6 6
7#include <memory> 7#include <memory>
8 8
9#include "core/file_sys/vfs.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs_types.h"
10 11
11namespace FileSys { 12namespace FileSys {
12 13
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 664a47e7f..956da68f7 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -8,11 +8,11 @@
8#include <fmt/ostream.h> 8#include <fmt/ostream.h>
9 9
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/crypto/key_manager.h"
11#include "core/file_sys/card_image.h" 12#include "core/file_sys/card_image.h"
12#include "core/file_sys/content_archive.h" 13#include "core/file_sys/content_archive.h"
13#include "core/file_sys/nca_metadata.h" 14#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/partition_filesystem.h" 15#include "core/file_sys/partition_filesystem.h"
15#include "core/file_sys/romfs.h"
16#include "core/file_sys/submission_package.h" 16#include "core/file_sys/submission_package.h"
17#include "core/file_sys/vfs_concat.h" 17#include "core/file_sys/vfs_concat.h"
18#include "core/file_sys/vfs_offset.h" 18#include "core/file_sys/vfs_offset.h"
@@ -31,7 +31,8 @@ constexpr std::array partition_names{
31 31
32XCI::XCI(VirtualFile file_) 32XCI::XCI(VirtualFile file_)
33 : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, 33 : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
34 partitions(partition_names.size()), partitions_raw(partition_names.size()) { 34 partitions(partition_names.size()),
35 partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
35 if (file->ReadObject(&header) != sizeof(GamecardHeader)) { 36 if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
36 status = Loader::ResultStatus::ErrorBadXCIHeader; 37 status = Loader::ResultStatus::ErrorBadXCIHeader;
37 return; 38 return;
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index e1b136426..2d0a0f285 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -9,9 +9,12 @@
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/crypto/key_manager.h"
13#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
14 13
14namespace Core::Crypto {
15class KeyManager;
16}
17
15namespace Loader { 18namespace Loader {
16enum class ResultStatus : u16; 19enum class ResultStatus : u16;
17} 20}
@@ -140,6 +143,6 @@ private:
140 143
141 u64 update_normal_partition_end; 144 u64 update_normal_partition_end;
142 145
143 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 146 Core::Crypto::KeyManager& keys;
144}; 147};
145} // namespace FileSys 148} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 5039341c7..426fb6bb5 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -10,10 +10,10 @@
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/crypto/aes_util.h" 11#include "core/crypto/aes_util.h"
12#include "core/crypto/ctr_encryption_layer.h" 12#include "core/crypto/ctr_encryption_layer.h"
13#include "core/crypto/key_manager.h"
13#include "core/file_sys/content_archive.h" 14#include "core/file_sys/content_archive.h"
14#include "core/file_sys/nca_patch.h" 15#include "core/file_sys/nca_patch.h"
15#include "core/file_sys/partition_filesystem.h" 16#include "core/file_sys/partition_filesystem.h"
16#include "core/file_sys/romfs.h"
17#include "core/file_sys/vfs_offset.h" 17#include "core/file_sys/vfs_offset.h"
18#include "core/loader/loader.h" 18#include "core/loader/loader.h"
19 19
@@ -119,7 +119,8 @@ static bool IsValidNCA(const NCAHeader& header) {
119} 119}
120 120
121NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) 121NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset)
122 : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) { 122 : file(std::move(file_)),
123 bktr_base_romfs(std::move(bktr_base_romfs_)), keys{Core::Crypto::KeyManager::Instance()} {
123 if (file == nullptr) { 124 if (file == nullptr) {
124 status = Loader::ResultStatus::ErrorNullFile; 125 status = Loader::ResultStatus::ErrorNullFile;
125 return; 126 return;
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index d25cbcf91..69292232a 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -158,7 +158,7 @@ private:
158 bool encrypted = false; 158 bool encrypted = false;
159 bool is_update = false; 159 bool is_update = false;
160 160
161 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 161 Core::Crypto::KeyManager& keys;
162}; 162};
163 163
164} // namespace FileSys 164} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 63cd2eead..b0a130345 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -5,6 +5,7 @@
5#include "common/string_util.h" 5#include "common/string_util.h"
6#include "common/swap.h" 6#include "common/swap.h"
7#include "core/file_sys/control_metadata.h" 7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/vfs.h"
8 9
9namespace FileSys { 10namespace FileSys {
10 11
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index e37b2fadf..9ab86e35b 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -10,7 +10,7 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs_types.h"
14 14
15namespace FileSys { 15namespace FileSys {
16 16
diff --git a/src/core/file_sys/kernel_executable.cpp b/src/core/file_sys/kernel_executable.cpp
index 76313679d..ef93ef3ed 100644
--- a/src/core/file_sys/kernel_executable.cpp
+++ b/src/core/file_sys/kernel_executable.cpp
@@ -2,9 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
5#include "common/string_util.h" 7#include "common/string_util.h"
6#include "core/file_sys/kernel_executable.h" 8#include "core/file_sys/kernel_executable.h"
7#include "core/file_sys/vfs_offset.h" 9#include "core/file_sys/vfs_offset.h"
10#include "core/loader/loader.h"
8 11
9namespace FileSys { 12namespace FileSys {
10 13
diff --git a/src/core/file_sys/kernel_executable.h b/src/core/file_sys/kernel_executable.h
index 324a57384..044c554d3 100644
--- a/src/core/file_sys/kernel_executable.h
+++ b/src/core/file_sys/kernel_executable.h
@@ -4,10 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <vector>
9
7#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h"
8#include "common/swap.h" 12#include "common/swap.h"
9#include "core/file_sys/vfs_types.h" 13#include "core/file_sys/vfs_types.h"
10#include "core/loader/loader.h" 14
15namespace Loader {
16enum class ResultStatus : u16;
17}
11 18
12namespace FileSys { 19namespace FileSys {
13 20
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 93d0df6b9..2d1476e3a 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -7,6 +7,7 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/swap.h" 8#include "common/swap.h"
9#include "core/file_sys/nca_metadata.h" 9#include "core/file_sys/nca_metadata.h"
10#include "core/file_sys/vfs.h"
10 11
11namespace FileSys { 12namespace FileSys {
12 13
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index 1f82fff0a..53535e5f5 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -10,7 +10,7 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs_types.h"
14 14
15namespace FileSys { 15namespace FileSys {
16class CNMT; 16class CNMT;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 846986736..48a2ed4d4 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -21,7 +21,7 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
21 magic == Common::MakeMagic('P', 'F', 'S', '0'); 21 magic == Common::MakeMagic('P', 'F', 'S', '0');
22} 22}
23 23
24PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) { 24PartitionFilesystem::PartitionFilesystem(VirtualFile file) {
25 // At least be as large as the header 25 // At least be as large as the header
26 if (file->GetSize() < sizeof(Header)) { 26 if (file->GetSize() < sizeof(Header)) {
27 status = Loader::ResultStatus::ErrorBadPFSHeader; 27 status = Loader::ResultStatus::ErrorBadPFSHeader;
@@ -89,11 +89,11 @@ std::map<std::string, u64> PartitionFilesystem::GetFileSizes() const {
89 return sizes; 89 return sizes;
90} 90}
91 91
92std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const { 92std::vector<VirtualFile> PartitionFilesystem::GetFiles() const {
93 return pfs_files; 93 return pfs_files;
94} 94}
95 95
96std::vector<std::shared_ptr<VfsDirectory>> PartitionFilesystem::GetSubdirectories() const { 96std::vector<VirtualDir> PartitionFilesystem::GetSubdirectories() const {
97 return {}; 97 return {};
98} 98}
99 99
@@ -101,7 +101,7 @@ std::string PartitionFilesystem::GetName() const {
101 return is_hfs ? "HFS0" : "PFS0"; 101 return is_hfs ? "HFS0" : "PFS0";
102} 102}
103 103
104std::shared_ptr<VfsDirectory> PartitionFilesystem::GetParentDirectory() const { 104VirtualDir PartitionFilesystem::GetParentDirectory() const {
105 // TODO(DarkLordZach): Add support for nested containers. 105 // TODO(DarkLordZach): Add support for nested containers.
106 return nullptr; 106 return nullptr;
107} 107}
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index 279193b19..0f831148e 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -24,7 +24,7 @@ namespace FileSys {
24 */ 24 */
25class PartitionFilesystem : public ReadOnlyVfsDirectory { 25class PartitionFilesystem : public ReadOnlyVfsDirectory {
26public: 26public:
27 explicit PartitionFilesystem(std::shared_ptr<VfsFile> file); 27 explicit PartitionFilesystem(VirtualFile file);
28 ~PartitionFilesystem() override; 28 ~PartitionFilesystem() override;
29 29
30 Loader::ResultStatus GetStatus() const; 30 Loader::ResultStatus GetStatus() const;
@@ -32,10 +32,10 @@ public:
32 std::map<std::string, u64> GetFileOffsets() const; 32 std::map<std::string, u64> GetFileOffsets() const;
33 std::map<std::string, u64> GetFileSizes() const; 33 std::map<std::string, u64> GetFileSizes() const;
34 34
35 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 35 std::vector<VirtualFile> GetFiles() const override;
36 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 36 std::vector<VirtualDir> GetSubdirectories() const override;
37 std::string GetName() const override; 37 std::string GetName() const override;
38 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 38 VirtualDir GetParentDirectory() const override;
39 void PrintDebugInfo() const; 39 void PrintDebugInfo() const;
40 40
41private: 41private:
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 729dbb5f4..c228d253e 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -49,8 +49,7 @@ std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
49 return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]); 49 return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
50} 50}
51 51
52std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir, 52VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) {
53 std::string_view name) {
54#ifdef _WIN32 53#ifdef _WIN32
55 return dir->GetSubdirectory(name); 54 return dir->GetSubdirectory(name);
56#else 55#else
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index f4cb918dd..532f4995f 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -6,10 +6,11 @@
6 6
7#include <map> 7#include <map>
8#include <memory> 8#include <memory>
9#include <optional>
9#include <string> 10#include <string>
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "core/file_sys/nca_metadata.h" 12#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs_types.h"
13#include "core/memory/dmnt_cheat_types.h" 14#include "core/memory/dmnt_cheat_types.h"
14 15
15namespace Core { 16namespace Core {
@@ -31,8 +32,7 @@ std::string FormatTitleVersion(u32 version,
31 32
32// Returns a directory with name matching name case-insensitive. Returns nullptr if directory 33// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
33// doesn't have a directory with name. 34// doesn't have a directory with name.
34std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir, 35VirtualDir FindSubdirectoryCaseless(VirtualDir dir, std::string_view name);
35 std::string_view name);
36 36
37// A centralized class to manage patches to games. 37// A centralized class to manage patches to games.
38class PatchManager { 38class PatchManager {
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 43169bf9f..9cf49bf44 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -7,6 +7,7 @@
7 7
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/file_sys/program_metadata.h" 9#include "core/file_sys/program_metadata.h"
10#include "core/file_sys/vfs.h"
10#include "core/loader/loader.h" 11#include "core/loader/loader.h"
11 12
12namespace FileSys { 13namespace FileSys {
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 35069972b..455532567 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -9,7 +9,7 @@
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs_types.h"
13 13
14namespace Loader { 14namespace Loader {
15enum class ResultStatus : u16; 15enum class ResultStatus : u16;
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
index 2fd07ed04..82e683782 100644
--- a/src/core/file_sys/romfs.h
+++ b/src/core/file_sys/romfs.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include "core/file_sys/vfs.h" 7#include "core/file_sys/vfs.h"
9 8
10namespace FileSys { 9namespace FileSys {
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index 6f732e4d8..cb56d8f2d 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -5,8 +5,8 @@
5#include <memory> 5#include <memory>
6#include "core/file_sys/registered_cache.h" 6#include "core/file_sys/registered_cache.h"
7#include "core/file_sys/sdmc_factory.h" 7#include "core/file_sys/sdmc_factory.h"
8#include "core/file_sys/vfs.h"
8#include "core/file_sys/xts_archive.h" 9#include "core/file_sys/xts_archive.h"
9#include "core/settings.h"
10 10
11namespace FileSys { 11namespace FileSys {
12 12
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index 42dc4e08a..2bb92ba93 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs_types.h"
9#include "core/hle/result.h" 9#include "core/hle/result.h"
10 10
11namespace FileSys { 11namespace FileSys {
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 175a8266a..b9ce93b7c 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -54,7 +54,7 @@ void SetTicketKeys(const std::vector<VirtualFile>& files) {
54 54
55NSP::NSP(VirtualFile file_) 55NSP::NSP(VirtualFile file_)
56 : file(std::move(file_)), status{Loader::ResultStatus::Success}, 56 : file(std::move(file_)), status{Loader::ResultStatus::Success},
57 pfs(std::make_shared<PartitionFilesystem>(file)) { 57 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
58 if (pfs->GetStatus() != Loader::ResultStatus::Success) { 58 if (pfs->GetStatus() != Loader::ResultStatus::Success) {
59 status = pfs->GetStatus(); 59 status = pfs->GetStatus();
60 return; 60 return;
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index cf89de6a9..2db5e46b8 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -10,6 +10,10 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs.h"
12 12
13namespace Core::Crypto {
14class KeyManager;
15}
16
13namespace Loader { 17namespace Loader {
14enum class ResultStatus : u16; 18enum class ResultStatus : u16;
15} 19}
@@ -73,7 +77,7 @@ private:
73 std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; 77 std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
74 std::vector<VirtualFile> ticket_files; 78 std::vector<VirtualFile> ticket_files;
75 79
76 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 80 Core::Crypto::KeyManager& keys;
77 81
78 VirtualFile romfs; 82 VirtualFile romfs;
79 VirtualDir exefs; 83 VirtualDir exefs;
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index ccf5966d0..24c58e7ae 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -15,8 +15,9 @@
15#include "common/hex_util.h" 15#include "common/hex_util.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/crypto/aes_util.h" 17#include "core/crypto/aes_util.h"
18#include "core/crypto/key_manager.h"
18#include "core/crypto/xts_encryption_layer.h" 19#include "core/crypto/xts_encryption_layer.h"
19#include "core/file_sys/partition_filesystem.h" 20#include "core/file_sys/content_archive.h"
20#include "core/file_sys/vfs_offset.h" 21#include "core/file_sys/vfs_offset.h"
21#include "core/file_sys/xts_archive.h" 22#include "core/file_sys/xts_archive.h"
22#include "core/loader/loader.h" 23#include "core/loader/loader.h"
@@ -43,7 +44,9 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
43 return true; 44 return true;
44} 45}
45 46
46NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { 47NAX::NAX(VirtualFile file_)
48 : header(std::make_unique<NAXHeader>()),
49 file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
47 std::string path = Common::FS::SanitizePath(file->GetFullPath()); 50 std::string path = Common::FS::SanitizePath(file->GetFullPath());
48 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca", 51 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
49 std::regex_constants::ECMAScript | 52 std::regex_constants::ECMAScript |
@@ -60,7 +63,8 @@ NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::m
60} 63}
61 64
62NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id) 65NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
63 : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { 66 : header(std::make_unique<NAXHeader>()),
67 file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
64 Core::Crypto::SHA256Hash hash{}; 68 Core::Crypto::SHA256Hash hash{};
65 mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0); 69 mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
66 status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0], 70 status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index 563531bb6..c472e226e 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -9,12 +9,16 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/crypto/key_manager.h" 11#include "core/crypto/key_manager.h"
12#include "core/file_sys/content_archive.h"
13#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
14#include "core/loader/loader.h" 13
14namespace Loader {
15enum class ResultStatus : u16;
16}
15 17
16namespace FileSys { 18namespace FileSys {
17 19
20class NCA;
21
18struct NAXHeader { 22struct NAXHeader {
19 std::array<u8, 0x20> hmac; 23 std::array<u8, 0x20> hmac;
20 u64_le magic; 24 u64_le magic;
@@ -62,6 +66,6 @@ private:
62 66
63 VirtualFile dec_file; 67 VirtualFile dec_file;
64 68
65 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 69 Core::Crypto::KeyManager& keys;
66}; 70};
67} // namespace FileSys 71} // namespace FileSys
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index 91ecc30ab..e2e3bbbb3 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h"
7#include "common/math_util.h" 8#include "common/math_util.h"
8 9
9namespace Layout { 10namespace Layout {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index cabe8d418..f2b0fe2fd 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -219,6 +219,7 @@ struct KernelCore::Impl {
219 return static_cast<u32>(system.GetCpuManager().CurrentCore()); 219 return static_cast<u32>(system.GetCpuManager().CurrentCore());
220 } 220 }
221 } 221 }
222 std::unique_lock lock{register_thread_mutex};
222 const auto it = host_thread_ids.find(this_id); 223 const auto it = host_thread_ids.find(this_id);
223 if (it == host_thread_ids.end()) { 224 if (it == host_thread_ids.end()) {
224 return Core::INVALID_HOST_THREAD_ID; 225 return Core::INVALID_HOST_THREAD_ID;
@@ -324,7 +325,7 @@ struct KernelCore::Impl {
324 std::unordered_map<std::thread::id, u32> host_thread_ids; 325 std::unordered_map<std::thread::id, u32> host_thread_ids;
325 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; 326 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
326 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; 327 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
327 std::mutex register_thread_mutex; 328 mutable std::mutex register_thread_mutex;
328 329
329 // Kernel memory management 330 // Kernel memory management
330 std::unique_ptr<Memory::MemoryManager> memory_manager; 331 std::unique_ptr<Memory::MemoryManager> memory_manager;
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index a4b234424..5cbd3b912 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -756,7 +756,11 @@ void Scheduler::SwitchToCurrent() {
756 current_thread = selected_thread; 756 current_thread = selected_thread;
757 is_context_switch_pending = false; 757 is_context_switch_pending = false;
758 } 758 }
759 while (!is_context_switch_pending) { 759 const auto is_switch_pending = [this] {
760 std::scoped_lock lock{guard};
761 return is_context_switch_pending;
762 };
763 do {
760 if (current_thread != nullptr && !current_thread->IsHLEThread()) { 764 if (current_thread != nullptr && !current_thread->IsHLEThread()) {
761 current_thread->context_guard.lock(); 765 current_thread->context_guard.lock();
762 if (!current_thread->IsRunnable()) { 766 if (!current_thread->IsRunnable()) {
@@ -775,7 +779,7 @@ void Scheduler::SwitchToCurrent() {
775 next_context = &idle_thread->GetHostContext(); 779 next_context = &idle_thread->GetHostContext();
776 } 780 }
777 Common::Fiber::YieldTo(switch_fiber, *next_context); 781 Common::Fiber::YieldTo(switch_fiber, *next_context);
778 } 782 } while (!is_switch_pending());
779 } 783 }
780} 784}
781 785
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 26fd87f58..649128be4 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -844,8 +844,7 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
844 return; 844 return;
845 } 845 }
846 846
847 FileSys::StorageId id; 847 FileSys::StorageId id{};
848
849 switch (parameters.space_id) { 848 switch (parameters.space_id) {
850 case FileSys::SaveDataSpaceId::NandUser: 849 case FileSys::SaveDataSpaceId::NandUser:
851 id = FileSys::StorageId::NandUser; 850 id = FileSys::StorageId::NandUser;
@@ -857,6 +856,10 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
857 case FileSys::SaveDataSpaceId::NandSystem: 856 case FileSys::SaveDataSpaceId::NandSystem:
858 id = FileSys::StorageId::NandSystem; 857 id = FileSys::StorageId::NandSystem;
859 break; 858 break;
859 case FileSys::SaveDataSpaceId::TemporaryStorage:
860 case FileSys::SaveDataSpaceId::ProperSystem:
861 case FileSys::SaveDataSpaceId::SafeMode:
862 UNREACHABLE();
860 } 863 }
861 864
862 auto filesystem = 865 auto filesystem =
@@ -902,7 +905,14 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
902 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData 905 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
903 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); 906 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
904 907
905 LOG_WARNING(Service_FS, "(STUBBED) called, flags={}", flags); 908 LOG_WARNING(Service_FS,
909 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
910 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
911 "attribute.type={}, attribute.rank={}, attribute.index={}",
912 flags, static_cast<u32>(parameters.space_id), parameters.attribute.title_id,
913 parameters.attribute.user_id[1], parameters.attribute.user_id[0],
914 parameters.attribute.save_id, static_cast<u32>(parameters.attribute.type),
915 static_cast<u32>(parameters.attribute.rank), parameters.attribute.index);
906 916
907 IPC::ResponseBuilder rb{ctx, 3}; 917 IPC::ResponseBuilder rb{ctx, 3};
908 rb.Push(RESULT_SUCCESS); 918 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 45fde8df2..e742497e1 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -574,6 +574,22 @@ Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMo
574 return gyroscope_zero_drift_mode; 574 return gyroscope_zero_drift_mode;
575} 575}
576 576
577void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
578 const auto npad_index_1 = NPadIdToIndex(npad_id_1);
579 const auto npad_index_2 = NPadIdToIndex(npad_id_2);
580
581 // If the controllers at both npad indices form a pair of left and right joycons, merge them.
582 // Otherwise, do nothing.
583 if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft &&
584 connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) ||
585 (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
586 connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
587 // Disconnect the joycon at the second id and connect the dual joycon at the first index.
588 DisconnectNPad(npad_id_2);
589 AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
590 }
591}
592
577void Controller_NPad::StartLRAssignmentMode() { 593void Controller_NPad::StartLRAssignmentMode() {
578 // Nothing internally is used for lr assignment mode. Since we have the ability to set the 594 // Nothing internally is used for lr assignment mode. Since we have the ability to set the
579 // controller types from boot, it doesn't really matter about showing a selection screen 595 // controller types from boot, it doesn't really matter about showing a selection screen
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 75ce5b731..ad25c6fbf 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -134,6 +134,7 @@ public:
134 void ConnectAllDisconnectedControllers(); 134 void ConnectAllDisconnectedControllers();
135 void ClearAllControllers(); 135 void ClearAllControllers();
136 136
137 void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2);
137 void StartLRAssignmentMode(); 138 void StartLRAssignmentMode();
138 void StopLRAssignmentMode(); 139 void StopLRAssignmentMode();
139 bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); 140 bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index e326f8f5c..0df395e85 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -40,9 +40,14 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
40 cur_entry.sampling_number = last_entry.sampling_number + 1; 40 cur_entry.sampling_number = last_entry.sampling_number + 1;
41 cur_entry.sampling_number2 = cur_entry.sampling_number; 41 cur_entry.sampling_number2 = cur_entry.sampling_number;
42 42
43 const auto [x, y, pressed] = touch_device->GetStatus(); 43 bool pressed = false;
44 float x, y;
45 std::tie(x, y, pressed) = touch_device->GetStatus();
44 auto& touch_entry = cur_entry.states[0]; 46 auto& touch_entry = cur_entry.states[0];
45 touch_entry.attribute.raw = 0; 47 touch_entry.attribute.raw = 0;
48 if (!pressed && touch_btn_device) {
49 std::tie(x, y, pressed) = touch_btn_device->GetStatus();
50 }
46 if (pressed && Settings::values.touchscreen.enabled) { 51 if (pressed && Settings::values.touchscreen.enabled) {
47 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); 52 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
48 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); 53 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
@@ -63,5 +68,10 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
63 68
64void Controller_Touchscreen::OnLoadInputDevices() { 69void Controller_Touchscreen::OnLoadInputDevices() {
65 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device); 70 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device);
71 if (Settings::values.use_touch_from_button) {
72 touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button");
73 } else {
74 touch_btn_device.reset();
75 }
66} 76}
67} // namespace Service::HID 77} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index a1d97269e..4d9042adc 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -68,6 +68,7 @@ private:
68 "TouchScreenSharedMemory is an invalid size"); 68 "TouchScreenSharedMemory is an invalid size");
69 TouchScreenSharedMemory shared_memory{}; 69 TouchScreenSharedMemory shared_memory{};
70 std::unique_ptr<Input::TouchDevice> touch_device; 70 std::unique_ptr<Input::TouchDevice> touch_device;
71 std::unique_ptr<Input::TouchDevice> touch_btn_device;
71 s64_le last_touch{}; 72 s64_le last_touch{};
72}; 73};
73} // namespace Service::HID 74} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 33416b5dd..bd3c2f26b 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -671,13 +671,15 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
671 671
672void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 672void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
673 IPC::RequestParser rp{ctx}; 673 IPC::RequestParser rp{ctx};
674 const auto unknown_1{rp.Pop<u32>()}; 674 const auto npad_id_1{rp.Pop<u32>()};
675 const auto unknown_2{rp.Pop<u32>()}; 675 const auto npad_id_2{rp.Pop<u32>()};
676 const auto applet_resource_user_id{rp.Pop<u64>()}; 676 const auto applet_resource_user_id{rp.Pop<u64>()};
677 677
678 LOG_WARNING(Service_HID, 678 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
679 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", 679 npad_id_1, npad_id_2, applet_resource_user_id);
680 unknown_1, unknown_2, applet_resource_user_id); 680
681 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
682 controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
681 683
682 IPC::ResponseBuilder rb{ctx, 2}; 684 IPC::ResponseBuilder rb{ctx, 2};
683 rb.Push(RESULT_SUCCESS); 685 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 01ddcdbd6..2e9d95195 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -9,6 +9,7 @@
9#include "core/hle/kernel/writable_event.h" 9#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nifm/nifm.h" 10#include "core/hle/service/nifm/nifm.h"
11#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12#include "core/network/network.h"
12#include "core/settings.h" 13#include "core/settings.h"
13 14
14namespace Service::NIFM { 15namespace Service::NIFM {
@@ -174,6 +175,16 @@ private:
174 IPC::ResponseBuilder rb{ctx, 2}; 175 IPC::ResponseBuilder rb{ctx, 2};
175 rb.Push(RESULT_SUCCESS); 176 rb.Push(RESULT_SUCCESS);
176 } 177 }
178 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
179 LOG_WARNING(Service_NIFM, "(STUBBED) called");
180
181 const auto [ipv4, error] = Network::GetHostIPv4Address();
182 UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
183
184 IPC::ResponseBuilder rb{ctx, 3};
185 rb.Push(RESULT_SUCCESS);
186 rb.PushRaw(ipv4);
187 }
177 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 188 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
178 LOG_DEBUG(Service_NIFM, "called"); 189 LOG_DEBUG(Service_NIFM, "called");
179 190
@@ -235,7 +246,7 @@ IGeneralService::IGeneralService(Core::System& system)
235 {9, nullptr, "SetNetworkProfile"}, 246 {9, nullptr, "SetNetworkProfile"},
236 {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, 247 {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"},
237 {11, nullptr, "GetScanDataOld"}, 248 {11, nullptr, "GetScanDataOld"},
238 {12, nullptr, "GetCurrentIpAddress"}, 249 {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"},
239 {13, nullptr, "GetCurrentAccessPointOld"}, 250 {13, nullptr, "GetCurrentAccessPointOld"},
240 {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"}, 251 {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"},
241 {15, nullptr, "GetCurrentIpConfigInfo"}, 252 {15, nullptr, "GetCurrentIpConfigInfo"},
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 886450be2..58ee1f712 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -5,6 +5,7 @@
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/file_sys/control_metadata.h" 6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h" 7#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/vfs.h"
8#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 10#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/ns/errors.h" 11#include "core/hle/service/ns/errors.h"
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index fa5347af9..538f28495 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -246,7 +246,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
246 PSC::InstallInterfaces(*sm); 246 PSC::InstallInterfaces(*sm);
247 PSM::InstallInterfaces(*sm); 247 PSM::InstallInterfaces(*sm);
248 Set::InstallInterfaces(*sm); 248 Set::InstallInterfaces(*sm);
249 Sockets::InstallInterfaces(*sm); 249 Sockets::InstallInterfaces(*sm, system);
250 SPL::InstallInterfaces(*sm); 250 SPL::InstallInterfaces(*sm);
251 SSL::InstallInterfaces(*sm); 251 SSL::InstallInterfaces(*sm);
252 Time::InstallInterfaces(system); 252 Time::InstallInterfaces(system);
diff --git a/src/core/hle/service/sockets/blocking_worker.h b/src/core/hle/service/sockets/blocking_worker.h
new file mode 100644
index 000000000..31ef6b821
--- /dev/null
+++ b/src/core/hle/service/sockets/blocking_worker.h
@@ -0,0 +1,162 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <memory>
9#include <string>
10#include <string_view>
11#include <thread>
12#include <variant>
13#include <vector>
14
15#include <fmt/format.h>
16
17#include "common/assert.h"
18#include "common/microprofile.h"
19#include "common/thread.h"
20#include "core/core.h"
21#include "core/hle/kernel/hle_ipc.h"
22#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/thread.h"
24#include "core/hle/kernel/writable_event.h"
25
26namespace Service::Sockets {
27
28/**
29 * Worker abstraction to execute blocking calls on host without blocking the guest thread
30 *
31 * @tparam Service Service where the work is executed
32 * @tparam ...Types Types of work to execute
33 */
34template <class Service, class... Types>
35class BlockingWorker {
36 using This = BlockingWorker<Service, Types...>;
37 using WorkVariant = std::variant<std::monostate, Types...>;
38
39public:
40 /// Create a new worker
41 static std::unique_ptr<This> Create(Core::System& system, Service* service,
42 std::string_view name) {
43 return std::unique_ptr<This>(new This(system, service, name));
44 }
45
46 ~BlockingWorker() {
47 while (!is_available.load(std::memory_order_relaxed)) {
48 // Busy wait until work is finished
49 std::this_thread::yield();
50 }
51 // Monostate means to exit the thread
52 work = std::monostate{};
53 work_event.Set();
54 thread.join();
55 }
56
57 /**
58 * Try to capture the worker to send work after a success
59 * @returns True when the worker has been successfully captured
60 */
61 bool TryCapture() {
62 bool expected = true;
63 return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed,
64 std::memory_order_relaxed);
65 }
66
67 /**
68 * Send work to this worker abstraction
69 * @see TryCapture must be called before attempting to call this function
70 */
71 template <class Work>
72 void SendWork(Work new_work) {
73 ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured");
74 work = std::move(new_work);
75 work_event.Set();
76 }
77
78 /// Generate a callback for @see SleepClientThread
79 template <class Work>
80 auto Callback() {
81 return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx,
82 Kernel::ThreadWakeupReason reason) {
83 ASSERT(reason == Kernel::ThreadWakeupReason::Signal);
84 std::get<Work>(work).Response(ctx);
85 is_available.store(true);
86 };
87 }
88
89 /// Get kernel event that will be signalled by the worker when the host operation finishes
90 std::shared_ptr<Kernel::WritableEvent> KernelEvent() const {
91 return kernel_event;
92 }
93
94private:
95 explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) {
96 auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name));
97 kernel_event = std::move(pair.writable);
98 thread = std::thread([this, &system, service, name] { Run(system, service, name); });
99 }
100
101 void Run(Core::System& system, Service* service, std::string_view name) {
102 system.RegisterHostThread();
103
104 const std::string thread_name = fmt::format("yuzu:{}", name);
105 MicroProfileOnThreadCreate(thread_name.c_str());
106 Common::SetCurrentThreadName(thread_name.c_str());
107
108 bool keep_running = true;
109 while (keep_running) {
110 work_event.Wait();
111
112 const auto visit_fn = [service, &keep_running](auto&& w) {
113 using T = std::decay_t<decltype(w)>;
114 if constexpr (std::is_same_v<T, std::monostate>) {
115 keep_running = false;
116 } else {
117 w.Execute(service);
118 }
119 };
120 std::visit(visit_fn, work);
121
122 kernel_event->Signal();
123 }
124 }
125
126 std::thread thread;
127 WorkVariant work;
128 Common::Event work_event;
129 std::shared_ptr<Kernel::WritableEvent> kernel_event;
130 std::atomic_bool is_available{true};
131};
132
133template <class Service, class... Types>
134class BlockingWorkerPool {
135 using Worker = BlockingWorker<Service, Types...>;
136
137public:
138 explicit BlockingWorkerPool(Core::System& system_, Service* service_)
139 : system{system_}, service{service_} {}
140
141 /// Returns a captured worker thread, creating new ones if necessary
142 Worker* CaptureWorker() {
143 for (auto& worker : workers) {
144 if (worker->TryCapture()) {
145 return worker.get();
146 }
147 }
148 auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size()));
149 [[maybe_unused]] const bool success = new_worker->TryCapture();
150 ASSERT(success);
151
152 return workers.emplace_back(std::move(new_worker)).get();
153 }
154
155private:
156 Core::System& system;
157 Service* const service;
158
159 std::vector<std::unique_ptr<Worker>> workers;
160};
161
162} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 8d4952c0e..803505452 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -2,18 +2,138 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
6#include <memory>
7#include <string>
8#include <utility>
9#include <vector>
10
11#include <fmt/format.h>
12
13#include "common/microprofile.h"
14#include "common/thread.h"
5#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/thread.h"
6#include "core/hle/service/sockets/bsd.h" 17#include "core/hle/service/sockets/bsd.h"
18#include "core/hle/service/sockets/sockets_translate.h"
19#include "core/network/network.h"
20#include "core/network/sockets.h"
7 21
8namespace Service::Sockets { 22namespace Service::Sockets {
9 23
24namespace {
25
26bool IsConnectionBased(Type type) {
27 switch (type) {
28 case Type::STREAM:
29 return true;
30 case Type::DGRAM:
31 return false;
32 default:
33 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
34 return false;
35 }
36}
37
38} // Anonymous namespace
39
40void BSD::PollWork::Execute(BSD* bsd) {
41 std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
42}
43
44void BSD::PollWork::Response(Kernel::HLERequestContext& ctx) {
45 ctx.WriteBuffer(write_buffer);
46
47 IPC::ResponseBuilder rb{ctx, 4};
48 rb.Push(RESULT_SUCCESS);
49 rb.Push<s32>(ret);
50 rb.PushEnum(bsd_errno);
51}
52
53void BSD::AcceptWork::Execute(BSD* bsd) {
54 std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
55}
56
57void BSD::AcceptWork::Response(Kernel::HLERequestContext& ctx) {
58 ctx.WriteBuffer(write_buffer);
59
60 IPC::ResponseBuilder rb{ctx, 5};
61 rb.Push(RESULT_SUCCESS);
62 rb.Push<s32>(ret);
63 rb.PushEnum(bsd_errno);
64 rb.Push<u32>(static_cast<u32>(write_buffer.size()));
65}
66
67void BSD::ConnectWork::Execute(BSD* bsd) {
68 bsd_errno = bsd->ConnectImpl(fd, addr);
69}
70
71void BSD::ConnectWork::Response(Kernel::HLERequestContext& ctx) {
72 IPC::ResponseBuilder rb{ctx, 4};
73 rb.Push(RESULT_SUCCESS);
74 rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
75 rb.PushEnum(bsd_errno);
76}
77
78void BSD::RecvWork::Execute(BSD* bsd) {
79 std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
80}
81
82void BSD::RecvWork::Response(Kernel::HLERequestContext& ctx) {
83 ctx.WriteBuffer(message);
84
85 IPC::ResponseBuilder rb{ctx, 4};
86 rb.Push(RESULT_SUCCESS);
87 rb.Push<s32>(ret);
88 rb.PushEnum(bsd_errno);
89}
90
91void BSD::RecvFromWork::Execute(BSD* bsd) {
92 std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
93}
94
95void BSD::RecvFromWork::Response(Kernel::HLERequestContext& ctx) {
96 ctx.WriteBuffer(message, 0);
97 if (!addr.empty()) {
98 ctx.WriteBuffer(addr, 1);
99 }
100
101 IPC::ResponseBuilder rb{ctx, 5};
102 rb.Push(RESULT_SUCCESS);
103 rb.Push<s32>(ret);
104 rb.PushEnum(bsd_errno);
105 rb.Push<u32>(static_cast<u32>(addr.size()));
106}
107
108void BSD::SendWork::Execute(BSD* bsd) {
109 std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
110}
111
112void BSD::SendWork::Response(Kernel::HLERequestContext& ctx) {
113 IPC::ResponseBuilder rb{ctx, 4};
114 rb.Push(RESULT_SUCCESS);
115 rb.Push<s32>(ret);
116 rb.PushEnum(bsd_errno);
117}
118
119void BSD::SendToWork::Execute(BSD* bsd) {
120 std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
121}
122
123void BSD::SendToWork::Response(Kernel::HLERequestContext& ctx) {
124 IPC::ResponseBuilder rb{ctx, 4};
125 rb.Push(RESULT_SUCCESS);
126 rb.Push<s32>(ret);
127 rb.PushEnum(bsd_errno);
128}
129
10void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { 130void BSD::RegisterClient(Kernel::HLERequestContext& ctx) {
11 LOG_WARNING(Service, "(STUBBED) called"); 131 LOG_WARNING(Service, "(STUBBED) called");
12 132
13 IPC::ResponseBuilder rb{ctx, 3}; 133 IPC::ResponseBuilder rb{ctx, 3};
14 134
15 rb.Push(RESULT_SUCCESS); 135 rb.Push(RESULT_SUCCESS);
16 rb.Push<u32>(0); // bsd errno 136 rb.Push<s32>(0); // bsd errno
17} 137}
18 138
19void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { 139void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
@@ -26,20 +146,19 @@ void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
26 146
27void BSD::Socket(Kernel::HLERequestContext& ctx) { 147void BSD::Socket(Kernel::HLERequestContext& ctx) {
28 IPC::RequestParser rp{ctx}; 148 IPC::RequestParser rp{ctx};
149 const u32 domain = rp.Pop<u32>();
150 const u32 type = rp.Pop<u32>();
151 const u32 protocol = rp.Pop<u32>();
29 152
30 u32 domain = rp.Pop<u32>(); 153 LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
31 u32 type = rp.Pop<u32>();
32 u32 protocol = rp.Pop<u32>();
33
34 LOG_WARNING(Service, "(STUBBED) called domain={} type={} protocol={}", domain, type, protocol);
35 154
36 u32 fd = next_fd++; 155 const auto [fd, bsd_errno] = SocketImpl(static_cast<Domain>(domain), static_cast<Type>(type),
156 static_cast<Protocol>(protocol));
37 157
38 IPC::ResponseBuilder rb{ctx, 4}; 158 IPC::ResponseBuilder rb{ctx, 4};
39
40 rb.Push(RESULT_SUCCESS); 159 rb.Push(RESULT_SUCCESS);
41 rb.Push<u32>(fd); 160 rb.Push<s32>(fd);
42 rb.Push<u32>(0); // bsd errno 161 rb.PushEnum(bsd_errno);
43} 162}
44 163
45void BSD::Select(Kernel::HLERequestContext& ctx) { 164void BSD::Select(Kernel::HLERequestContext& ctx) {
@@ -52,67 +171,663 @@ void BSD::Select(Kernel::HLERequestContext& ctx) {
52 rb.Push<u32>(0); // bsd errno 171 rb.Push<u32>(0); // bsd errno
53} 172}
54 173
174void BSD::Poll(Kernel::HLERequestContext& ctx) {
175 IPC::RequestParser rp{ctx};
176 const s32 nfds = rp.Pop<s32>();
177 const s32 timeout = rp.Pop<s32>();
178
179 LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout);
180
181 ExecuteWork(ctx, "BSD:Poll", timeout != 0,
182 PollWork{
183 .nfds = nfds,
184 .timeout = timeout,
185 .read_buffer = ctx.ReadBuffer(),
186 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
187 });
188}
189
190void BSD::Accept(Kernel::HLERequestContext& ctx) {
191 IPC::RequestParser rp{ctx};
192 const s32 fd = rp.Pop<s32>();
193
194 LOG_DEBUG(Service, "called. fd={}", fd);
195
196 ExecuteWork(ctx, "BSD:Accept", IsBlockingSocket(fd),
197 AcceptWork{
198 .fd = fd,
199 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
200 });
201}
202
55void BSD::Bind(Kernel::HLERequestContext& ctx) { 203void BSD::Bind(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service, "(STUBBED) called"); 204 IPC::RequestParser rp{ctx};
205 const s32 fd = rp.Pop<s32>();
57 206
58 IPC::ResponseBuilder rb{ctx, 4}; 207 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
59 208
60 rb.Push(RESULT_SUCCESS); 209 BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
61 rb.Push<u32>(0); // ret
62 rb.Push<u32>(0); // bsd errno
63} 210}
64 211
65void BSD::Connect(Kernel::HLERequestContext& ctx) { 212void BSD::Connect(Kernel::HLERequestContext& ctx) {
66 LOG_WARNING(Service, "(STUBBED) called"); 213 IPC::RequestParser rp{ctx};
214 const s32 fd = rp.Pop<s32>();
67 215
68 IPC::ResponseBuilder rb{ctx, 4}; 216 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
217
218 ExecuteWork(ctx, "BSD:Connect", IsBlockingSocket(fd),
219 ConnectWork{
220 .fd = fd,
221 .addr = ctx.ReadBuffer(),
222 });
223}
224
225void BSD::GetPeerName(Kernel::HLERequestContext& ctx) {
226 IPC::RequestParser rp{ctx};
227 const s32 fd = rp.Pop<s32>();
228
229 LOG_DEBUG(Service, "called. fd={}", fd);
69 230
231 std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
232 const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
233
234 ctx.WriteBuffer(write_buffer);
235
236 IPC::ResponseBuilder rb{ctx, 5};
70 rb.Push(RESULT_SUCCESS); 237 rb.Push(RESULT_SUCCESS);
71 rb.Push<u32>(0); // ret 238 rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
72 rb.Push<u32>(0); // bsd errno 239 rb.PushEnum(bsd_errno);
240 rb.Push<u32>(static_cast<u32>(write_buffer.size()));
241}
242
243void BSD::GetSockName(Kernel::HLERequestContext& ctx) {
244 IPC::RequestParser rp{ctx};
245 const s32 fd = rp.Pop<s32>();
246
247 LOG_DEBUG(Service, "called. fd={}", fd);
248
249 std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
250 const Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
251
252 ctx.WriteBuffer(write_buffer);
253
254 IPC::ResponseBuilder rb{ctx, 5};
255 rb.Push(RESULT_SUCCESS);
256 rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
257 rb.PushEnum(bsd_errno);
258 rb.Push<u32>(static_cast<u32>(write_buffer.size()));
73} 259}
74 260
75void BSD::Listen(Kernel::HLERequestContext& ctx) { 261void BSD::Listen(Kernel::HLERequestContext& ctx) {
76 LOG_WARNING(Service, "(STUBBED) called"); 262 IPC::RequestParser rp{ctx};
263 const s32 fd = rp.Pop<s32>();
264 const s32 backlog = rp.Pop<s32>();
77 265
78 IPC::ResponseBuilder rb{ctx, 4}; 266 LOG_DEBUG(Service, "called. fd={} backlog={}", fd, backlog);
267
268 BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
269}
270
271void BSD::Fcntl(Kernel::HLERequestContext& ctx) {
272 IPC::RequestParser rp{ctx};
273 const s32 fd = rp.Pop<s32>();
274 const s32 cmd = rp.Pop<s32>();
275 const s32 arg = rp.Pop<s32>();
79 276
277 LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
278
279 const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg);
280
281 IPC::ResponseBuilder rb{ctx, 4};
80 rb.Push(RESULT_SUCCESS); 282 rb.Push(RESULT_SUCCESS);
81 rb.Push<u32>(0); // ret 283 rb.Push<s32>(ret);
82 rb.Push<u32>(0); // bsd errno 284 rb.PushEnum(bsd_errno);
83} 285}
84 286
85void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { 287void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
86 LOG_WARNING(Service, "(STUBBED) called"); 288 IPC::RequestParser rp{ctx};
87 289
88 IPC::ResponseBuilder rb{ctx, 4}; 290 const s32 fd = rp.Pop<s32>();
291 const u32 level = rp.Pop<u32>();
292 const OptName optname = static_cast<OptName>(rp.Pop<u32>());
89 293
90 rb.Push(RESULT_SUCCESS); 294 const std::vector<u8> buffer = ctx.ReadBuffer();
91 rb.Push<u32>(0); // ret 295 const u8* optval = buffer.empty() ? nullptr : buffer.data();
92 rb.Push<u32>(0); // bsd errno 296 size_t optlen = buffer.size();
297
298 std::array<u64, 2> values;
299 if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) {
300 std::memcpy(values.data(), buffer.data(), sizeof(values));
301 optlen = sizeof(values);
302 optval = reinterpret_cast<const u8*>(values.data());
303 }
304
305 LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level,
306 static_cast<u32>(optname), optlen);
307
308 BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval));
309}
310
311void BSD::Shutdown(Kernel::HLERequestContext& ctx) {
312 IPC::RequestParser rp{ctx};
313
314 const s32 fd = rp.Pop<s32>();
315 const s32 how = rp.Pop<s32>();
316
317 LOG_DEBUG(Service, "called. fd={} how={}", fd, how);
318
319 BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
320}
321
322void BSD::Recv(Kernel::HLERequestContext& ctx) {
323 IPC::RequestParser rp{ctx};
324
325 const s32 fd = rp.Pop<s32>();
326 const u32 flags = rp.Pop<u32>();
327
328 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize());
329
330 ExecuteWork(ctx, "BSD:Recv", IsBlockingSocket(fd),
331 RecvWork{
332 .fd = fd,
333 .flags = flags,
334 .message = std::vector<u8>(ctx.GetWriteBufferSize()),
335 });
336}
337
338void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
339 IPC::RequestParser rp{ctx};
340
341 const s32 fd = rp.Pop<s32>();
342 const u32 flags = rp.Pop<u32>();
343
344 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags,
345 ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1));
346
347 ExecuteWork(ctx, "BSD:RecvFrom", IsBlockingSocket(fd),
348 RecvFromWork{
349 .fd = fd,
350 .flags = flags,
351 .message = std::vector<u8>(ctx.GetWriteBufferSize(0)),
352 .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)),
353 });
354}
355
356void BSD::Send(Kernel::HLERequestContext& ctx) {
357 IPC::RequestParser rp{ctx};
358
359 const s32 fd = rp.Pop<s32>();
360 const u32 flags = rp.Pop<u32>();
361
362 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize());
363
364 ExecuteWork(ctx, "BSD:Send", IsBlockingSocket(fd),
365 SendWork{
366 .fd = fd,
367 .flags = flags,
368 .message = ctx.ReadBuffer(),
369 });
93} 370}
94 371
95void BSD::SendTo(Kernel::HLERequestContext& ctx) { 372void BSD::SendTo(Kernel::HLERequestContext& ctx) {
96 LOG_WARNING(Service, "(STUBBED) called"); 373 IPC::RequestParser rp{ctx};
374 const s32 fd = rp.Pop<s32>();
375 const u32 flags = rp.Pop<u32>();
376
377 LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags,
378 ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1));
379
380 ExecuteWork(ctx, "BSD:SendTo", IsBlockingSocket(fd),
381 SendToWork{
382 .fd = fd,
383 .flags = flags,
384 .message = ctx.ReadBuffer(0),
385 .addr = ctx.ReadBuffer(1),
386 });
387}
97 388
98 IPC::ResponseBuilder rb{ctx, 4}; 389void BSD::Write(Kernel::HLERequestContext& ctx) {
390 IPC::RequestParser rp{ctx};
391 const s32 fd = rp.Pop<s32>();
99 392
100 rb.Push(RESULT_SUCCESS); 393 LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize());
101 rb.Push<u32>(0); // ret 394
102 rb.Push<u32>(0); // bsd errno 395 ExecuteWork(ctx, "BSD:Write", IsBlockingSocket(fd),
396 SendWork{
397 .fd = fd,
398 .flags = 0,
399 .message = ctx.ReadBuffer(),
400 });
103} 401}
104 402
105void BSD::Close(Kernel::HLERequestContext& ctx) { 403void BSD::Close(Kernel::HLERequestContext& ctx) {
106 LOG_WARNING(Service, "(STUBBED) called"); 404 IPC::RequestParser rp{ctx};
405 const s32 fd = rp.Pop<s32>();
406
407 LOG_DEBUG(Service, "called. fd={}", fd);
408
409 BuildErrnoResponse(ctx, CloseImpl(fd));
410}
411
412template <typename Work>
413void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
414 bool is_blocking, Work work) {
415 if (!is_blocking) {
416 work.Execute(this);
417 work.Response(ctx);
418 return;
419 }
420
421 // Signal a dummy response to make IPC validation happy
422 // This will be overwritten by the SleepClientThread callback
423 work.Response(ctx);
424
425 auto worker = worker_pool.CaptureWorker();
426
427 ctx.SleepClientThread(std::string(sleep_reason), std::numeric_limits<u64>::max(),
428 worker->Callback<Work>(), worker->KernelEvent());
429
430 worker->SendWork(std::move(work));
431}
432
433std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
434 if (type == Type::SEQPACKET) {
435 UNIMPLEMENTED_MSG("SOCK_SEQPACKET errno management");
436 } else if (type == Type::RAW && (domain != Domain::INET || protocol != Protocol::ICMP)) {
437 UNIMPLEMENTED_MSG("SOCK_RAW errno management");
438 }
439
440 [[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0;
441 UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
442 type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
443
444 const s32 fd = FindFreeFileDescriptorHandle();
445 if (fd < 0) {
446 LOG_ERROR(Service, "No more file descriptors available");
447 return {-1, Errno::MFILE};
448 }
449
450 FileDescriptor& descriptor = file_descriptors[fd].emplace();
451 // ENONMEM might be thrown here
452
453 LOG_INFO(Service, "New socket fd={}", fd);
454
455 descriptor.socket = std::make_unique<Network::Socket>();
456 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol));
457 descriptor.is_connection_based = IsConnectionBased(type);
458
459 return {fd, Errno::SUCCESS};
460}
107 461
462std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
463 s32 nfds, s32 timeout) {
464 if (write_buffer.size() < nfds * sizeof(PollFD)) {
465 return {-1, Errno::INVAL};
466 }
467
468 if (nfds == 0) {
469 // When no entries are provided, -1 is returned with errno zero
470 return {-1, Errno::SUCCESS};
471 }
472
473 const size_t length = std::min(read_buffer.size(), write_buffer.size());
474 std::vector<PollFD> fds(nfds);
475 std::memcpy(fds.data(), read_buffer.data(), length);
476
477 if (timeout >= 0) {
478 const s64 seconds = timeout / 1000;
479 const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
480
481 if (seconds < 0) {
482 return {-1, Errno::INVAL};
483 }
484 if (nanoseconds > 999'999'999) {
485 return {-1, Errno::INVAL};
486 }
487 } else if (timeout != -1) {
488 return {-1, Errno::INVAL};
489 }
490
491 for (PollFD& pollfd : fds) {
492 ASSERT(pollfd.revents == 0);
493
494 if (pollfd.fd > MAX_FD || pollfd.fd < 0) {
495 LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
496 pollfd.revents = 0;
497 return {0, Errno::SUCCESS};
498 }
499
500 std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
501 if (!descriptor) {
502 LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd);
503 pollfd.revents = POLL_NVAL;
504 return {0, Errno::SUCCESS};
505 }
506 }
507
508 std::vector<Network::PollFD> host_pollfds(fds.size());
509 std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) {
510 Network::PollFD result;
511 result.socket = file_descriptors[pollfd.fd]->socket.get();
512 result.events = TranslatePollEventsToHost(pollfd.events);
513 result.revents = 0;
514 return result;
515 });
516
517 const auto result = Network::Poll(host_pollfds, timeout);
518
519 const size_t num = host_pollfds.size();
520 for (size_t i = 0; i < num; ++i) {
521 fds[i].revents = TranslatePollEventsToGuest(host_pollfds[i].revents);
522 }
523 std::memcpy(write_buffer.data(), fds.data(), length);
524
525 return Translate(result);
526}
527
528std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
529 if (!IsFileDescriptorValid(fd)) {
530 return {-1, Errno::BADF};
531 }
532
533 const s32 new_fd = FindFreeFileDescriptorHandle();
534 if (new_fd < 0) {
535 LOG_ERROR(Service, "No more file descriptors available");
536 return {-1, Errno::MFILE};
537 }
538
539 FileDescriptor& descriptor = *file_descriptors[fd];
540 auto [result, bsd_errno] = descriptor.socket->Accept();
541 if (bsd_errno != Network::Errno::SUCCESS) {
542 return {-1, Translate(bsd_errno)};
543 }
544
545 FileDescriptor& new_descriptor = file_descriptors[new_fd].emplace();
546 new_descriptor.socket = std::move(result.socket);
547 new_descriptor.is_connection_based = descriptor.is_connection_based;
548
549 ASSERT(write_buffer.size() == sizeof(SockAddrIn));
550 const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
551 std::memcpy(write_buffer.data(), &guest_addr_in, sizeof(guest_addr_in));
552
553 return {new_fd, Errno::SUCCESS};
554}
555
556Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
557 if (!IsFileDescriptorValid(fd)) {
558 return Errno::BADF;
559 }
560 ASSERT(addr.size() == sizeof(SockAddrIn));
561 SockAddrIn addr_in;
562 std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
563
564 return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
565}
566
567Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) {
568 if (!IsFileDescriptorValid(fd)) {
569 return Errno::BADF;
570 }
571
572 UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
573 SockAddrIn addr_in;
574 std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
575
576 return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
577}
578
579Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
580 if (!IsFileDescriptorValid(fd)) {
581 return Errno::BADF;
582 }
583
584 const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
585 if (bsd_errno != Network::Errno::SUCCESS) {
586 return Translate(bsd_errno);
587 }
588 const SockAddrIn guest_addrin = Translate(addr_in);
589
590 ASSERT(write_buffer.size() == sizeof(guest_addrin));
591 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
592 return Translate(bsd_errno);
593}
594
595Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
596 if (!IsFileDescriptorValid(fd)) {
597 return Errno::BADF;
598 }
599
600 const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
601 if (bsd_errno != Network::Errno::SUCCESS) {
602 return Translate(bsd_errno);
603 }
604 const SockAddrIn guest_addrin = Translate(addr_in);
605
606 ASSERT(write_buffer.size() == sizeof(guest_addrin));
607 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
608 return Translate(bsd_errno);
609}
610
611Errno BSD::ListenImpl(s32 fd, s32 backlog) {
612 if (!IsFileDescriptorValid(fd)) {
613 return Errno::BADF;
614 }
615 return Translate(file_descriptors[fd]->socket->Listen(backlog));
616}
617
618std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
619 if (!IsFileDescriptorValid(fd)) {
620 return {-1, Errno::BADF};
621 }
622
623 FileDescriptor& descriptor = *file_descriptors[fd];
624
625 switch (cmd) {
626 case FcntlCmd::GETFL:
627 ASSERT(arg == 0);
628 return {descriptor.flags, Errno::SUCCESS};
629 case FcntlCmd::SETFL: {
630 const bool enable = (arg & FLAG_O_NONBLOCK) != 0;
631 const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
632 if (bsd_errno != Errno::SUCCESS) {
633 return {-1, bsd_errno};
634 }
635 descriptor.flags = arg;
636 return {0, Errno::SUCCESS};
637 }
638 default:
639 UNIMPLEMENTED_MSG("Unimplemented cmd={}", static_cast<int>(cmd));
640 return {-1, Errno::SUCCESS};
641 }
642}
643
644Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
645 UNIMPLEMENTED_IF(level != 0xffff); // SOL_SOCKET
646
647 if (!IsFileDescriptorValid(fd)) {
648 return Errno::BADF;
649 }
650
651 Network::Socket* const socket = file_descriptors[fd]->socket.get();
652
653 if (optname == OptName::LINGER) {
654 ASSERT(optlen == sizeof(Linger));
655 Linger linger;
656 std::memcpy(&linger, optval, sizeof(linger));
657 ASSERT(linger.onoff == 0 || linger.onoff == 1);
658
659 return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
660 }
661
662 ASSERT(optlen == sizeof(u32));
663 u32 value;
664 std::memcpy(&value, optval, sizeof(value));
665
666 switch (optname) {
667 case OptName::REUSEADDR:
668 ASSERT(value == 0 || value == 1);
669 return Translate(socket->SetReuseAddr(value != 0));
670 case OptName::BROADCAST:
671 ASSERT(value == 0 || value == 1);
672 return Translate(socket->SetBroadcast(value != 0));
673 case OptName::SNDBUF:
674 return Translate(socket->SetSndBuf(value));
675 case OptName::RCVBUF:
676 return Translate(socket->SetRcvBuf(value));
677 case OptName::SNDTIMEO:
678 return Translate(socket->SetSndTimeo(value));
679 case OptName::RCVTIMEO:
680 return Translate(socket->SetRcvTimeo(value));
681 default:
682 UNIMPLEMENTED_MSG("Unimplemented optname={}", static_cast<int>(optname));
683 return Errno::SUCCESS;
684 }
685}
686
687Errno BSD::ShutdownImpl(s32 fd, s32 how) {
688 if (!IsFileDescriptorValid(fd)) {
689 return Errno::BADF;
690 }
691 const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
692 return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
693}
694
695std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
696 if (!IsFileDescriptorValid(fd)) {
697 return {-1, Errno::BADF};
698 }
699 return Translate(file_descriptors[fd]->socket->Recv(flags, message));
700}
701
702std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
703 std::vector<u8>& addr) {
704 if (!IsFileDescriptorValid(fd)) {
705 return {-1, Errno::BADF};
706 }
707
708 FileDescriptor& descriptor = *file_descriptors[fd];
709
710 Network::SockAddrIn addr_in{};
711 Network::SockAddrIn* p_addr_in = nullptr;
712 if (descriptor.is_connection_based) {
713 // Connection based file descriptors (e.g. TCP) zero addr
714 addr.clear();
715 } else {
716 p_addr_in = &addr_in;
717 }
718
719 // Apply flags
720 if ((flags & FLAG_MSG_DONTWAIT) != 0) {
721 flags &= ~FLAG_MSG_DONTWAIT;
722 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
723 descriptor.socket->SetNonBlock(true);
724 }
725 }
726
727 const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
728
729 // Restore original state
730 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
731 descriptor.socket->SetNonBlock(false);
732 }
733
734 if (p_addr_in) {
735 if (ret < 0) {
736 addr.clear();
737 } else {
738 ASSERT(addr.size() == sizeof(SockAddrIn));
739 const SockAddrIn result = Translate(addr_in);
740 std::memcpy(addr.data(), &result, sizeof(result));
741 }
742 }
743
744 return {ret, bsd_errno};
745}
746
747std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) {
748 if (!IsFileDescriptorValid(fd)) {
749 return {-1, Errno::BADF};
750 }
751 return Translate(file_descriptors[fd]->socket->Send(message, flags));
752}
753
754std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
755 const std::vector<u8>& addr) {
756 if (!IsFileDescriptorValid(fd)) {
757 return {-1, Errno::BADF};
758 }
759
760 Network::SockAddrIn addr_in;
761 Network::SockAddrIn* p_addr_in = nullptr;
762 if (!addr.empty()) {
763 ASSERT(addr.size() == sizeof(SockAddrIn));
764 SockAddrIn guest_addr_in;
765 std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in));
766 addr_in = Translate(guest_addr_in);
767 }
768
769 return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
770}
771
772Errno BSD::CloseImpl(s32 fd) {
773 if (!IsFileDescriptorValid(fd)) {
774 return Errno::BADF;
775 }
776
777 const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
778 if (bsd_errno != Errno::SUCCESS) {
779 return bsd_errno;
780 }
781
782 LOG_INFO(Service, "Close socket fd={}", fd);
783
784 file_descriptors[fd].reset();
785 return bsd_errno;
786}
787
788s32 BSD::FindFreeFileDescriptorHandle() noexcept {
789 for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
790 if (!file_descriptors[fd]) {
791 return fd;
792 }
793 }
794 return -1;
795}
796
797bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
798 if (fd > MAX_FD || fd < 0) {
799 LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
800 return false;
801 }
802 if (!file_descriptors[fd]) {
803 LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
804 return false;
805 }
806 return true;
807}
808
809bool BSD::IsBlockingSocket(s32 fd) const noexcept {
810 // Inform invalid sockets as non-blocking
811 // This way we avoid using a worker thread as it will fail without blocking host
812 if (fd > MAX_FD || fd < 0) {
813 return false;
814 }
815 if (!file_descriptors[fd]) {
816 return false;
817 }
818 return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0;
819}
820
821void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept {
108 IPC::ResponseBuilder rb{ctx, 4}; 822 IPC::ResponseBuilder rb{ctx, 4};
109 823
110 rb.Push(RESULT_SUCCESS); 824 rb.Push(RESULT_SUCCESS);
111 rb.Push<u32>(0); // ret 825 rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
112 rb.Push<u32>(0); // bsd errno 826 rb.PushEnum(bsd_errno);
113} 827}
114 828
115BSD::BSD(const char* name) : ServiceFramework(name) { 829BSD::BSD(Core::System& system, const char* name)
830 : ServiceFramework(name), worker_pool{system, this} {
116 // clang-format off 831 // clang-format off
117 static const FunctionInfo functions[] = { 832 static const FunctionInfo functions[] = {
118 {0, &BSD::RegisterClient, "RegisterClient"}, 833 {0, &BSD::RegisterClient, "RegisterClient"},
@@ -121,25 +836,25 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
121 {3, nullptr, "SocketExempt"}, 836 {3, nullptr, "SocketExempt"},
122 {4, nullptr, "Open"}, 837 {4, nullptr, "Open"},
123 {5, &BSD::Select, "Select"}, 838 {5, &BSD::Select, "Select"},
124 {6, nullptr, "Poll"}, 839 {6, &BSD::Poll, "Poll"},
125 {7, nullptr, "Sysctl"}, 840 {7, nullptr, "Sysctl"},
126 {8, nullptr, "Recv"}, 841 {8, &BSD::Recv, "Recv"},
127 {9, nullptr, "RecvFrom"}, 842 {9, &BSD::RecvFrom, "RecvFrom"},
128 {10, nullptr, "Send"}, 843 {10, &BSD::Send, "Send"},
129 {11, &BSD::SendTo, "SendTo"}, 844 {11, &BSD::SendTo, "SendTo"},
130 {12, nullptr, "Accept"}, 845 {12, &BSD::Accept, "Accept"},
131 {13, &BSD::Bind, "Bind"}, 846 {13, &BSD::Bind, "Bind"},
132 {14, &BSD::Connect, "Connect"}, 847 {14, &BSD::Connect, "Connect"},
133 {15, nullptr, "GetPeerName"}, 848 {15, &BSD::GetPeerName, "GetPeerName"},
134 {16, nullptr, "GetSockName"}, 849 {16, &BSD::GetSockName, "GetSockName"},
135 {17, nullptr, "GetSockOpt"}, 850 {17, nullptr, "GetSockOpt"},
136 {18, &BSD::Listen, "Listen"}, 851 {18, &BSD::Listen, "Listen"},
137 {19, nullptr, "Ioctl"}, 852 {19, nullptr, "Ioctl"},
138 {20, nullptr, "Fcntl"}, 853 {20, &BSD::Fcntl, "Fcntl"},
139 {21, &BSD::SetSockOpt, "SetSockOpt"}, 854 {21, &BSD::SetSockOpt, "SetSockOpt"},
140 {22, nullptr, "Shutdown"}, 855 {22, &BSD::Shutdown, "Shutdown"},
141 {23, nullptr, "ShutdownAllSockets"}, 856 {23, nullptr, "ShutdownAllSockets"},
142 {24, nullptr, "Write"}, 857 {24, &BSD::Write, "Write"},
143 {25, nullptr, "Read"}, 858 {25, nullptr, "Read"},
144 {26, &BSD::Close, "Close"}, 859 {26, &BSD::Close, "Close"},
145 {27, nullptr, "DuplicateSocket"}, 860 {27, nullptr, "DuplicateSocket"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 3098e3baf..357531951 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -4,30 +4,174 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string_view>
9#include <vector>
10
11#include "common/common_types.h"
7#include "core/hle/kernel/hle_ipc.h" 12#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
14#include "core/hle/service/sockets/blocking_worker.h"
15#include "core/hle/service/sockets/sockets.h"
16
17namespace Core {
18class System;
19}
20
21namespace Network {
22class Socket;
23}
9 24
10namespace Service::Sockets { 25namespace Service::Sockets {
11 26
12class BSD final : public ServiceFramework<BSD> { 27class BSD final : public ServiceFramework<BSD> {
13public: 28public:
14 explicit BSD(const char* name); 29 explicit BSD(Core::System& system, const char* name);
15 ~BSD() override; 30 ~BSD() override;
16 31
17private: 32private:
33 /// Maximum number of file descriptors
34 static constexpr size_t MAX_FD = 128;
35
36 struct FileDescriptor {
37 std::unique_ptr<Network::Socket> socket;
38 s32 flags = 0;
39 bool is_connection_based = false;
40 };
41
42 struct PollWork {
43 void Execute(BSD* bsd);
44 void Response(Kernel::HLERequestContext& ctx);
45
46 s32 nfds;
47 s32 timeout;
48 std::vector<u8> read_buffer;
49 std::vector<u8> write_buffer;
50 s32 ret{};
51 Errno bsd_errno{};
52 };
53
54 struct AcceptWork {
55 void Execute(BSD* bsd);
56 void Response(Kernel::HLERequestContext& ctx);
57
58 s32 fd;
59 std::vector<u8> write_buffer;
60 s32 ret{};
61 Errno bsd_errno{};
62 };
63
64 struct ConnectWork {
65 void Execute(BSD* bsd);
66 void Response(Kernel::HLERequestContext& ctx);
67
68 s32 fd;
69 std::vector<u8> addr;
70 Errno bsd_errno{};
71 };
72
73 struct RecvWork {
74 void Execute(BSD* bsd);
75 void Response(Kernel::HLERequestContext& ctx);
76
77 s32 fd;
78 u32 flags;
79 std::vector<u8> message;
80 s32 ret{};
81 Errno bsd_errno{};
82 };
83
84 struct RecvFromWork {
85 void Execute(BSD* bsd);
86 void Response(Kernel::HLERequestContext& ctx);
87
88 s32 fd;
89 u32 flags;
90 std::vector<u8> message;
91 std::vector<u8> addr;
92 s32 ret{};
93 Errno bsd_errno{};
94 };
95
96 struct SendWork {
97 void Execute(BSD* bsd);
98 void Response(Kernel::HLERequestContext& ctx);
99
100 s32 fd;
101 u32 flags;
102 std::vector<u8> message;
103 s32 ret{};
104 Errno bsd_errno{};
105 };
106
107 struct SendToWork {
108 void Execute(BSD* bsd);
109 void Response(Kernel::HLERequestContext& ctx);
110
111 s32 fd;
112 u32 flags;
113 std::vector<u8> message;
114 std::vector<u8> addr;
115 s32 ret{};
116 Errno bsd_errno{};
117 };
118
18 void RegisterClient(Kernel::HLERequestContext& ctx); 119 void RegisterClient(Kernel::HLERequestContext& ctx);
19 void StartMonitoring(Kernel::HLERequestContext& ctx); 120 void StartMonitoring(Kernel::HLERequestContext& ctx);
20 void Socket(Kernel::HLERequestContext& ctx); 121 void Socket(Kernel::HLERequestContext& ctx);
21 void Select(Kernel::HLERequestContext& ctx); 122 void Select(Kernel::HLERequestContext& ctx);
123 void Poll(Kernel::HLERequestContext& ctx);
124 void Accept(Kernel::HLERequestContext& ctx);
22 void Bind(Kernel::HLERequestContext& ctx); 125 void Bind(Kernel::HLERequestContext& ctx);
23 void Connect(Kernel::HLERequestContext& ctx); 126 void Connect(Kernel::HLERequestContext& ctx);
127 void GetPeerName(Kernel::HLERequestContext& ctx);
128 void GetSockName(Kernel::HLERequestContext& ctx);
24 void Listen(Kernel::HLERequestContext& ctx); 129 void Listen(Kernel::HLERequestContext& ctx);
130 void Fcntl(Kernel::HLERequestContext& ctx);
25 void SetSockOpt(Kernel::HLERequestContext& ctx); 131 void SetSockOpt(Kernel::HLERequestContext& ctx);
132 void Shutdown(Kernel::HLERequestContext& ctx);
133 void Recv(Kernel::HLERequestContext& ctx);
134 void RecvFrom(Kernel::HLERequestContext& ctx);
135 void Send(Kernel::HLERequestContext& ctx);
26 void SendTo(Kernel::HLERequestContext& ctx); 136 void SendTo(Kernel::HLERequestContext& ctx);
137 void Write(Kernel::HLERequestContext& ctx);
27 void Close(Kernel::HLERequestContext& ctx); 138 void Close(Kernel::HLERequestContext& ctx);
28 139
29 /// Id to use for the next open file descriptor. 140 template <typename Work>
30 u32 next_fd = 1; 141 void ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
142 bool is_blocking, Work work);
143
144 std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
145 std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
146 s32 nfds, s32 timeout);
147 std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
148 Errno BindImpl(s32 fd, const std::vector<u8>& addr);
149 Errno ConnectImpl(s32 fd, const std::vector<u8>& addr);
150 Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
151 Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
152 Errno ListenImpl(s32 fd, s32 backlog);
153 std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
154 Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval);
155 Errno ShutdownImpl(s32 fd, s32 how);
156 std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
157 std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
158 std::vector<u8>& addr);
159 std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message);
160 std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
161 const std::vector<u8>& addr);
162 Errno CloseImpl(s32 fd);
163
164 s32 FindFreeFileDescriptorHandle() noexcept;
165 bool IsFileDescriptorValid(s32 fd) const noexcept;
166 bool IsBlockingSocket(s32 fd) const noexcept;
167
168 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
169
170 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
171
172 BlockingWorkerPool<BSD, PollWork, AcceptWork, ConnectWork, RecvWork, RecvFromWork, SendWork,
173 SendToWork>
174 worker_pool;
31}; 175};
32 176
33class BSDCFG final : public ServiceFramework<BSDCFG> { 177class BSDCFG final : public ServiceFramework<BSDCFG> {
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp
index 08d2d306a..1d27f7906 100644
--- a/src/core/hle/service/sockets/sockets.cpp
+++ b/src/core/hle/service/sockets/sockets.cpp
@@ -10,9 +10,9 @@
10 10
11namespace Service::Sockets { 11namespace Service::Sockets {
12 12
13void InstallInterfaces(SM::ServiceManager& service_manager) { 13void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
14 std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager); 14 std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager);
15 std::make_shared<BSD>("bsd:u")->InstallAsService(service_manager); 15 std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager);
16 std::make_shared<BSDCFG>()->InstallAsService(service_manager); 16 std::make_shared<BSDCFG>()->InstallAsService(service_manager);
17 17
18 std::make_shared<ETHC_C>()->InstallAsService(service_manager); 18 std::make_shared<ETHC_C>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index ca8a6a7e0..89a410076 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -4,11 +4,94 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
10namespace Core {
11class System;
12}
13
9namespace Service::Sockets { 14namespace Service::Sockets {
10 15
16enum class Errno : u32 {
17 SUCCESS = 0,
18 BADF = 9,
19 AGAIN = 11,
20 INVAL = 22,
21 MFILE = 24,
22 NOTCONN = 107,
23};
24
25enum class Domain : u32 {
26 INET = 2,
27};
28
29enum class Type : u32 {
30 STREAM = 1,
31 DGRAM = 2,
32 RAW = 3,
33 SEQPACKET = 5,
34};
35
36enum class Protocol : u32 {
37 UNSPECIFIED = 0,
38 ICMP = 1,
39 TCP = 6,
40 UDP = 17,
41};
42
43enum class OptName : u32 {
44 REUSEADDR = 0x4,
45 BROADCAST = 0x20,
46 LINGER = 0x80,
47 SNDBUF = 0x1001,
48 RCVBUF = 0x1002,
49 SNDTIMEO = 0x1005,
50 RCVTIMEO = 0x1006,
51};
52
53enum class ShutdownHow : s32 {
54 RD = 0,
55 WR = 1,
56 RDWR = 2,
57};
58
59enum class FcntlCmd : s32 {
60 GETFL = 3,
61 SETFL = 4,
62};
63
64struct SockAddrIn {
65 u8 len;
66 u8 family;
67 u16 portno;
68 std::array<u8, 4> ip;
69 std::array<u8, 8> zeroes;
70};
71
72struct PollFD {
73 s32 fd;
74 u16 events;
75 u16 revents;
76};
77
78struct Linger {
79 u32 onoff;
80 u32 linger;
81};
82
83constexpr u16 POLL_IN = 0x01;
84constexpr u16 POLL_PRI = 0x02;
85constexpr u16 POLL_OUT = 0x04;
86constexpr u16 POLL_ERR = 0x08;
87constexpr u16 POLL_HUP = 0x10;
88constexpr u16 POLL_NVAL = 0x20;
89
90constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
91
92constexpr u32 FLAG_O_NONBLOCK = 0x800;
93
11/// Registers all Sockets services with the specified service manager. 94/// Registers all Sockets services with the specified service manager.
12void InstallInterfaces(SM::ServiceManager& service_manager); 95void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
13 96
14} // namespace Service::Sockets 97} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
new file mode 100644
index 000000000..2be8f642d
--- /dev/null
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -0,0 +1,165 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <utility>
6
7#include "common/assert.h"
8#include "common/common_types.h"
9#include "core/hle/service/sockets/sockets.h"
10#include "core/hle/service/sockets/sockets_translate.h"
11#include "core/network/network.h"
12
13namespace Service::Sockets {
14
15Errno Translate(Network::Errno value) {
16 switch (value) {
17 case Network::Errno::SUCCESS:
18 return Errno::SUCCESS;
19 case Network::Errno::BADF:
20 return Errno::BADF;
21 case Network::Errno::AGAIN:
22 return Errno::AGAIN;
23 case Network::Errno::INVAL:
24 return Errno::INVAL;
25 case Network::Errno::MFILE:
26 return Errno::MFILE;
27 case Network::Errno::NOTCONN:
28 return Errno::NOTCONN;
29 default:
30 UNIMPLEMENTED_MSG("Unimplemented errno={}", static_cast<int>(value));
31 return Errno::SUCCESS;
32 }
33}
34
35std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
36 return {value.first, Translate(value.second)};
37}
38
39Network::Domain Translate(Domain domain) {
40 switch (domain) {
41 case Domain::INET:
42 return Network::Domain::INET;
43 default:
44 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
45 return {};
46 }
47}
48
49Domain Translate(Network::Domain domain) {
50 switch (domain) {
51 case Network::Domain::INET:
52 return Domain::INET;
53 default:
54 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
55 return {};
56 }
57}
58
59Network::Type Translate(Type type) {
60 switch (type) {
61 case Type::STREAM:
62 return Network::Type::STREAM;
63 case Type::DGRAM:
64 return Network::Type::DGRAM;
65 default:
66 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
67 }
68}
69
70Network::Protocol Translate(Type type, Protocol protocol) {
71 switch (protocol) {
72 case Protocol::UNSPECIFIED:
73 LOG_WARNING(Service, "Unspecified protocol, assuming protocol from type");
74 switch (type) {
75 case Type::DGRAM:
76 return Network::Protocol::UDP;
77 case Type::STREAM:
78 return Network::Protocol::TCP;
79 default:
80 return Network::Protocol::TCP;
81 }
82 case Protocol::TCP:
83 return Network::Protocol::TCP;
84 case Protocol::UDP:
85 return Network::Protocol::UDP;
86 default:
87 UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol));
88 return Network::Protocol::TCP;
89 }
90}
91
92u16 TranslatePollEventsToHost(u16 flags) {
93 u16 result = 0;
94 const auto translate = [&result, &flags](u16 from, u16 to) {
95 if ((flags & from) != 0) {
96 flags &= ~from;
97 result |= to;
98 }
99 };
100 translate(POLL_IN, Network::POLL_IN);
101 translate(POLL_PRI, Network::POLL_PRI);
102 translate(POLL_OUT, Network::POLL_OUT);
103 translate(POLL_ERR, Network::POLL_ERR);
104 translate(POLL_HUP, Network::POLL_HUP);
105 translate(POLL_NVAL, Network::POLL_NVAL);
106
107 UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags);
108 return result;
109}
110
111u16 TranslatePollEventsToGuest(u16 flags) {
112 u16 result = 0;
113 const auto translate = [&result, &flags](u16 from, u16 to) {
114 if ((flags & from) != 0) {
115 flags &= ~from;
116 result |= to;
117 }
118 };
119
120 translate(Network::POLL_IN, POLL_IN);
121 translate(Network::POLL_PRI, POLL_PRI);
122 translate(Network::POLL_OUT, POLL_OUT);
123 translate(Network::POLL_ERR, POLL_ERR);
124 translate(Network::POLL_HUP, POLL_HUP);
125 translate(Network::POLL_NVAL, POLL_NVAL);
126
127 UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags);
128 return result;
129}
130
131Network::SockAddrIn Translate(SockAddrIn value) {
132 ASSERT(value.len == 0 || value.len == sizeof(value));
133
134 Network::SockAddrIn result;
135 result.family = Translate(static_cast<Domain>(value.family));
136 result.ip = value.ip;
137 result.portno = value.portno >> 8 | value.portno << 8;
138 return result;
139}
140
141SockAddrIn Translate(Network::SockAddrIn value) {
142 SockAddrIn result;
143 result.len = sizeof(result);
144 result.family = static_cast<u8>(Translate(value.family));
145 result.portno = value.portno >> 8 | value.portno << 8;
146 result.ip = value.ip;
147 result.zeroes = {};
148 return result;
149}
150
151Network::ShutdownHow Translate(ShutdownHow how) {
152 switch (how) {
153 case ShutdownHow::RD:
154 return Network::ShutdownHow::RD;
155 case ShutdownHow::WR:
156 return Network::ShutdownHow::WR;
157 case ShutdownHow::RDWR:
158 return Network::ShutdownHow::RDWR;
159 default:
160 UNIMPLEMENTED_MSG("Unimplemented how={}", static_cast<int>(how));
161 return {};
162 }
163}
164
165} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h
new file mode 100644
index 000000000..8ed041e31
--- /dev/null
+++ b/src/core/hle/service/sockets/sockets_translate.h
@@ -0,0 +1,48 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <utility>
8
9#include "common/common_types.h"
10#include "core/hle/service/sockets/sockets.h"
11#include "core/network/network.h"
12
13namespace Service::Sockets {
14
15/// Translate abstract errno to guest errno
16Errno Translate(Network::Errno value);
17
18/// Translate abstract return value errno pair to guest return value errno pair
19std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
20
21/// Translate guest domain to abstract domain
22Network::Domain Translate(Domain domain);
23
24/// Translate abstract domain to guest domain
25Domain Translate(Network::Domain domain);
26
27/// Translate guest type to abstract type
28Network::Type Translate(Type type);
29
30/// Translate guest protocol to abstract protocol
31Network::Protocol Translate(Type type, Protocol protocol);
32
33/// Translate abstract poll event flags to guest poll event flags
34u16 TranslatePollEventsToHost(u16 flags);
35
36/// Translate guest poll event flags to abstract poll event flags
37u16 TranslatePollEventsToGuest(u16 flags);
38
39/// Translate guest socket address structure to abstract socket address structure
40Network::SockAddrIn Translate(SockAddrIn value);
41
42/// Translate abstract socket address structure to guest socket address structure
43SockAddrIn Translate(Network::SockAddrIn value);
44
45/// Translate guest shutdown mode to abstract shutdown mode
46Network::ShutdownHow Translate(ShutdownHow how);
47
48} // namespace Service::Sockets
diff --git a/src/core/settings.h b/src/core/settings.h
index 732c6a894..80f0d95a7 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -67,6 +67,11 @@ private:
67 Type local{}; 67 Type local{};
68}; 68};
69 69
70struct TouchFromButtonMap {
71 std::string name;
72 std::vector<std::string> buttons;
73};
74
70struct Values { 75struct Values {
71 // Audio 76 // Audio
72 std::string audio_device_id; 77 std::string audio_device_id;
@@ -145,15 +150,18 @@ struct Values {
145 ButtonsRaw debug_pad_buttons; 150 ButtonsRaw debug_pad_buttons;
146 AnalogsRaw debug_pad_analogs; 151 AnalogsRaw debug_pad_analogs;
147 152
148 std::string motion_device;
149
150 bool vibration_enabled; 153 bool vibration_enabled;
151 154
155 std::string motion_device;
156 std::string touch_device;
152 TouchscreenInput touchscreen; 157 TouchscreenInput touchscreen;
153 std::atomic_bool is_device_reload_pending{true}; 158 std::atomic_bool is_device_reload_pending{true};
159 bool use_touch_from_button;
160 int touch_from_button_map_index;
154 std::string udp_input_address; 161 std::string udp_input_address;
155 u16 udp_input_port; 162 u16 udp_input_port;
156 u8 udp_pad_index; 163 u8 udp_pad_index;
164 std::vector<TouchFromButtonMap> touch_from_button_maps;
157 165
158 // Data Storage 166 // Data Storage
159 bool use_virtual_sd; 167 bool use_virtual_sd;