diff options
29 files changed, 297 insertions, 389 deletions
diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp index 25700015a..dbb40da7c 100644 --- a/src/common/lz4_compression.cpp +++ b/src/common/lz4_compression.cpp | |||
| @@ -59,8 +59,7 @@ std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) | |||
| 59 | return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX); | 59 | return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, | 62 | std::vector<u8> DecompressDataLZ4(std::span<const u8> compressed, std::size_t uncompressed_size) { |
| 63 | std::size_t uncompressed_size) { | ||
| 64 | std::vector<u8> uncompressed(uncompressed_size); | 63 | std::vector<u8> uncompressed(uncompressed_size); |
| 65 | const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()), | 64 | const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()), |
| 66 | reinterpret_cast<char*>(uncompressed.data()), | 65 | reinterpret_cast<char*>(uncompressed.data()), |
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h index 87a4be1b0..1b4717595 100644 --- a/src/common/lz4_compression.h +++ b/src/common/lz4_compression.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <span> | ||
| 7 | #include <vector> | 8 | #include <vector> |
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| @@ -53,7 +54,7 @@ namespace Common::Compression { | |||
| 53 | * | 54 | * |
| 54 | * @return the decompressed data. | 55 | * @return the decompressed data. |
| 55 | */ | 56 | */ |
| 56 | [[nodiscard]] std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, | 57 | [[nodiscard]] std::vector<u8> DecompressDataLZ4(std::span<const u8> compressed, |
| 57 | std::size_t uncompressed_size); | 58 | std::size_t uncompressed_size); |
| 58 | 59 | ||
| 59 | } // namespace Common::Compression \ No newline at end of file | 60 | } // namespace Common::Compression |
diff --git a/src/common/tree.h b/src/common/tree.h index 9d2d0df4e..18faa4a48 100644 --- a/src/common/tree.h +++ b/src/common/tree.h | |||
| @@ -43,6 +43,8 @@ | |||
| 43 | * The maximum height of a red-black tree is 2lg (n+1). | 43 | * The maximum height of a red-black tree is 2lg (n+1). |
| 44 | */ | 44 | */ |
| 45 | 45 | ||
| 46 | #include "common/assert.h" | ||
| 47 | |||
| 46 | namespace Common { | 48 | namespace Common { |
| 47 | template <typename T> | 49 | template <typename T> |
| 48 | class RBHead { | 50 | class RBHead { |
| @@ -325,6 +327,10 @@ void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) { | |||
| 325 | while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root() && parent != nullptr) { | 327 | while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root() && parent != nullptr) { |
| 326 | if (RB_LEFT(parent) == elm) { | 328 | if (RB_LEFT(parent) == elm) { |
| 327 | tmp = RB_RIGHT(parent); | 329 | tmp = RB_RIGHT(parent); |
| 330 | if (!tmp) { | ||
| 331 | ASSERT_MSG(false, "tmp is invalid!"); | ||
| 332 | break; | ||
| 333 | } | ||
| 328 | if (RB_IS_RED(tmp)) { | 334 | if (RB_IS_RED(tmp)) { |
| 329 | RB_SET_BLACKRED(tmp, parent); | 335 | RB_SET_BLACKRED(tmp, parent); |
| 330 | RB_ROTATE_LEFT(head, parent, tmp); | 336 | RB_ROTATE_LEFT(head, parent, tmp); |
| @@ -366,6 +372,11 @@ void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) { | |||
| 366 | tmp = RB_LEFT(parent); | 372 | tmp = RB_LEFT(parent); |
| 367 | } | 373 | } |
| 368 | 374 | ||
| 375 | if (!tmp) { | ||
| 376 | ASSERT_MSG(false, "tmp is invalid!"); | ||
| 377 | break; | ||
| 378 | } | ||
| 379 | |||
| 369 | if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) && | 380 | if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) && |
| 370 | (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) { | 381 | (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) { |
| 371 | RB_SET_COLOR(tmp, EntryColor::Red); | 382 | RB_SET_COLOR(tmp, EntryColor::Red); |
diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp index 5f45459da..695b96a43 100644 --- a/src/common/zstd_compression.cpp +++ b/src/common/zstd_compression.cpp | |||
| @@ -32,7 +32,7 @@ std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_siz | |||
| 32 | return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT); | 32 | return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) { | 35 | std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed) { |
| 36 | const std::size_t decompressed_size = | 36 | const std::size_t decompressed_size = |
| 37 | ZSTD_getDecompressedSize(compressed.data(), compressed.size()); | 37 | ZSTD_getDecompressedSize(compressed.data(), compressed.size()); |
| 38 | std::vector<u8> decompressed(decompressed_size); | 38 | std::vector<u8> decompressed(decompressed_size); |
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h index c26a30ab9..bbce14f4e 100644 --- a/src/common/zstd_compression.h +++ b/src/common/zstd_compression.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <span> | ||
| 7 | #include <vector> | 8 | #include <vector> |
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| @@ -40,6 +41,6 @@ namespace Common::Compression { | |||
| 40 | * | 41 | * |
| 41 | * @return the decompressed data. | 42 | * @return the decompressed data. |
| 42 | */ | 43 | */ |
| 43 | [[nodiscard]] std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed); | 44 | [[nodiscard]] std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed); |
| 44 | 45 | ||
| 45 | } // namespace Common::Compression \ No newline at end of file | 46 | } // namespace Common::Compression |
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 497f35d23..61bda3786 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -80,16 +80,12 @@ public: | |||
| 80 | 80 | ||
| 81 | memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); | 81 | memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); |
| 82 | 82 | ||
| 83 | ctx.ClearIncomingObjects(); | ||
| 84 | |||
| 85 | IPC::CommandHeader header{}; | 83 | IPC::CommandHeader header{}; |
| 86 | 84 | ||
| 87 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory | 85 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory |
| 88 | // padding. | 86 | // padding. |
| 89 | u32 raw_data_size = ctx.IsTipc() | 87 | u32 raw_data_size = ctx.write_size = |
| 90 | ? normal_params_size - 1 | 88 | ctx.IsTipc() ? normal_params_size - 1 : normal_params_size; |
| 91 | : sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; | ||
| 92 | |||
| 93 | u32 num_handles_to_move{}; | 89 | u32 num_handles_to_move{}; |
| 94 | u32 num_domain_objects{}; | 90 | u32 num_domain_objects{}; |
| 95 | const bool always_move_handles{ | 91 | const bool always_move_handles{ |
| @@ -101,16 +97,20 @@ public: | |||
| 101 | } | 97 | } |
| 102 | 98 | ||
| 103 | if (ctx.Session()->IsDomain()) { | 99 | if (ctx.Session()->IsDomain()) { |
| 104 | raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / 4 + num_domain_objects); | 100 | raw_data_size += |
| 101 | static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); | ||
| 102 | ctx.write_size += num_domain_objects; | ||
| 105 | } | 103 | } |
| 106 | 104 | ||
| 107 | if (ctx.IsTipc()) { | 105 | if (ctx.IsTipc()) { |
| 108 | header.type.Assign(ctx.GetCommandType()); | 106 | header.type.Assign(ctx.GetCommandType()); |
| 107 | } else { | ||
| 108 | raw_data_size += static_cast<u32>(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 + | ||
| 109 | normal_params_size); | ||
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | ctx.data_size = static_cast<u32>(raw_data_size); | 112 | header.data_size.Assign(raw_data_size); |
| 112 | header.data_size.Assign(static_cast<u32>(raw_data_size)); | 113 | if (num_handles_to_copy || num_handles_to_move) { |
| 113 | if (num_handles_to_copy != 0 || num_handles_to_move != 0) { | ||
| 114 | header.enable_handle_descriptor.Assign(1); | 114 | header.enable_handle_descriptor.Assign(1); |
| 115 | } | 115 | } |
| 116 | PushRaw(header); | 116 | PushRaw(header); |
| @@ -143,7 +143,8 @@ public: | |||
| 143 | data_payload_index = index; | 143 | data_payload_index = index; |
| 144 | 144 | ||
| 145 | ctx.data_payload_offset = index; | 145 | ctx.data_payload_offset = index; |
| 146 | ctx.domain_offset = index + raw_data_size / 4; | 146 | ctx.write_size += index; |
| 147 | ctx.domain_offset = static_cast<u32>(index + raw_data_size / sizeof(u32)); | ||
| 147 | } | 148 | } |
| 148 | 149 | ||
| 149 | template <class T> | 150 | template <class T> |
| @@ -151,8 +152,8 @@ public: | |||
| 151 | if (context->Session()->IsDomain()) { | 152 | if (context->Session()->IsDomain()) { |
| 152 | context->AddDomainObject(std::move(iface)); | 153 | context->AddDomainObject(std::move(iface)); |
| 153 | } else { | 154 | } else { |
| 154 | // kernel.CurrentProcess()->GetResourceLimit()->Reserve( | 155 | kernel.CurrentProcess()->GetResourceLimit()->Reserve( |
| 155 | // Kernel::LimitableResource::Sessions, 1); | 156 | Kernel::LimitableResource::Sessions, 1); |
| 156 | 157 | ||
| 157 | auto* session = Kernel::KSession::Create(kernel); | 158 | auto* session = Kernel::KSession::Create(kernel); |
| 158 | session->Initialize(nullptr, iface->GetServiceName()); | 159 | session->Initialize(nullptr, iface->GetServiceName()); |
| @@ -167,24 +168,6 @@ public: | |||
| 167 | PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...)); | 168 | PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...)); |
| 168 | } | 169 | } |
| 169 | 170 | ||
| 170 | void ValidateHeader() { | ||
| 171 | const std::size_t num_domain_objects = context->NumDomainObjects(); | ||
| 172 | const std::size_t num_move_objects = context->NumMoveObjects(); | ||
| 173 | ASSERT_MSG(!num_domain_objects || !num_move_objects, | ||
| 174 | "cannot move normal handles and domain objects"); | ||
| 175 | ASSERT_MSG((index - data_payload_index) == normal_params_size, | ||
| 176 | "normal_params_size value is incorrect"); | ||
| 177 | ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move, | ||
| 178 | "num_objects_to_move value is incorrect"); | ||
| 179 | ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy, | ||
| 180 | "num_handles_to_copy value is incorrect"); | ||
| 181 | } | ||
| 182 | |||
| 183 | // Validate on destruction, as there shouldn't be any case where we don't want it | ||
| 184 | ~ResponseBuilder() { | ||
| 185 | ValidateHeader(); | ||
| 186 | } | ||
| 187 | |||
| 188 | void PushImpl(s8 value); | 171 | void PushImpl(s8 value); |
| 189 | void PushImpl(s16 value); | 172 | void PushImpl(s16 value); |
| 190 | void PushImpl(s32 value); | 173 | void PushImpl(s32 value); |
| @@ -404,7 +387,7 @@ public: | |||
| 404 | std::shared_ptr<T> PopIpcInterface() { | 387 | std::shared_ptr<T> PopIpcInterface() { |
| 405 | ASSERT(context->Session()->IsDomain()); | 388 | ASSERT(context->Session()->IsDomain()); |
| 406 | ASSERT(context->GetDomainMessageHeader().input_object_count > 0); | 389 | ASSERT(context->GetDomainMessageHeader().input_object_count > 0); |
| 407 | return context->GetDomainRequestHandler<T>(Pop<u32>() - 1); | 390 | return context->GetDomainHandler<T>(Pop<u32>() - 1); |
| 408 | } | 391 | } |
| 409 | }; | 392 | }; |
| 410 | 393 | ||
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 24700f7a5..9d069a78f 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -35,11 +35,11 @@ SessionRequestHandler::SessionRequestHandler() = default; | |||
| 35 | SessionRequestHandler::~SessionRequestHandler() = default; | 35 | SessionRequestHandler::~SessionRequestHandler() = default; |
| 36 | 36 | ||
| 37 | void SessionRequestHandler::ClientConnected(KServerSession* session) { | 37 | void SessionRequestHandler::ClientConnected(KServerSession* session) { |
| 38 | session->SetHleHandler(shared_from_this()); | 38 | session->SetSessionHandler(shared_from_this()); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void SessionRequestHandler::ClientDisconnected(KServerSession* session) { | 41 | void SessionRequestHandler::ClientDisconnected(KServerSession* session) { |
| 42 | session->SetHleHandler(nullptr); | 42 | session->SetSessionHandler(nullptr); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, | 45 | HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, |
| @@ -69,14 +69,10 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 69 | if (incoming) { | 69 | if (incoming) { |
| 70 | // Populate the object lists with the data in the IPC request. | 70 | // Populate the object lists with the data in the IPC request. |
| 71 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { | 71 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { |
| 72 | const u32 copy_handle{rp.Pop<Handle>()}; | 72 | incoming_copy_handles.push_back(rp.Pop<Handle>()); |
| 73 | copy_handles.push_back(copy_handle); | ||
| 74 | copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe()); | ||
| 75 | } | 73 | } |
| 76 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { | 74 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { |
| 77 | const u32 move_handle{rp.Pop<Handle>()}; | 75 | incoming_move_handles.push_back(rp.Pop<Handle>()); |
| 78 | move_handles.push_back(move_handle); | ||
| 79 | move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe()); | ||
| 80 | } | 76 | } |
| 81 | } else { | 77 | } else { |
| 82 | // For responses we just ignore the handles, they're empty and will be populated when | 78 | // For responses we just ignore the handles, they're empty and will be populated when |
| @@ -186,26 +182,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t | |||
| 186 | auto& owner_process = *requesting_thread.GetOwnerProcess(); | 182 | auto& owner_process = *requesting_thread.GetOwnerProcess(); |
| 187 | auto& handle_table = owner_process.GetHandleTable(); | 183 | auto& handle_table = owner_process.GetHandleTable(); |
| 188 | 184 | ||
| 189 | // The data_size already includes the payload header, the padding and the domain header. | 185 | for (auto& object : outgoing_copy_objects) { |
| 190 | std::size_t size{}; | ||
| 191 | |||
| 192 | if (IsTipc()) { | ||
| 193 | size = cmd_buf.size(); | ||
| 194 | } else { | ||
| 195 | size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; | ||
| 196 | if (Session()->IsDomain()) { | ||
| 197 | size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | for (auto& object : copy_objects) { | ||
| 202 | Handle handle{}; | 186 | Handle handle{}; |
| 203 | if (object) { | 187 | if (object) { |
| 204 | R_TRY(handle_table.Add(&handle, object)); | 188 | R_TRY(handle_table.Add(&handle, object)); |
| 205 | } | 189 | } |
| 206 | cmd_buf[current_offset++] = handle; | 190 | cmd_buf[current_offset++] = handle; |
| 207 | } | 191 | } |
| 208 | for (auto& object : move_objects) { | 192 | for (auto& object : outgoing_move_objects) { |
| 209 | Handle handle{}; | 193 | Handle handle{}; |
| 210 | if (object) { | 194 | if (object) { |
| 211 | R_TRY(handle_table.Add(&handle, object)); | 195 | R_TRY(handle_table.Add(&handle, object)); |
| @@ -220,9 +204,9 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t | |||
| 220 | // TODO(Subv): This completely ignores C buffers. | 204 | // TODO(Subv): This completely ignores C buffers. |
| 221 | 205 | ||
| 222 | if (Session()->IsDomain()) { | 206 | if (Session()->IsDomain()) { |
| 223 | current_offset = domain_offset - static_cast<u32>(domain_objects.size()); | 207 | current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); |
| 224 | for (const auto& object : domain_objects) { | 208 | for (const auto& object : outgoing_domain_objects) { |
| 225 | server_session->AppendDomainRequestHandler(object); | 209 | server_session->AppendDomainHandler(object); |
| 226 | cmd_buf[current_offset++] = | 210 | cmd_buf[current_offset++] = |
| 227 | static_cast<u32_le>(server_session->NumDomainRequestHandlers()); | 211 | static_cast<u32_le>(server_session->NumDomainRequestHandlers()); |
| 228 | } | 212 | } |
| @@ -230,7 +214,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t | |||
| 230 | 214 | ||
| 231 | // Copy the translated command buffer back into the thread's command buffer area. | 215 | // Copy the translated command buffer back into the thread's command buffer area. |
| 232 | memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), | 216 | memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), |
| 233 | size * sizeof(u32)); | 217 | write_size * sizeof(u32)); |
| 234 | 218 | ||
| 235 | return RESULT_SUCCESS; | 219 | return RESULT_SUCCESS; |
| 236 | } | 220 | } |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index e1b128281..b47e363cc 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -11,7 +11,8 @@ | |||
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <type_traits> | 12 | #include <type_traits> |
| 13 | #include <vector> | 13 | #include <vector> |
| 14 | #include <boost/container/small_vector.hpp> | 14 | |
| 15 | #include "common/assert.h" | ||
| 15 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 16 | #include "common/concepts.h" | 17 | #include "common/concepts.h" |
| 17 | #include "common/swap.h" | 18 | #include "common/swap.h" |
| @@ -84,6 +85,69 @@ public: | |||
| 84 | void ClientDisconnected(KServerSession* session); | 85 | void ClientDisconnected(KServerSession* session); |
| 85 | }; | 86 | }; |
| 86 | 87 | ||
| 88 | using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; | ||
| 89 | |||
| 90 | /** | ||
| 91 | * Manages the underlying HLE requests for a session, and whether (or not) the session should be | ||
| 92 | * treated as a domain. This is managed separately from server sessions, as this state is shared | ||
| 93 | * when objects are cloned. | ||
| 94 | */ | ||
| 95 | class SessionRequestManager final { | ||
| 96 | public: | ||
| 97 | SessionRequestManager() = default; | ||
| 98 | |||
| 99 | bool IsDomain() const { | ||
| 100 | return is_domain; | ||
| 101 | } | ||
| 102 | |||
| 103 | void ConvertToDomain() { | ||
| 104 | domain_handlers = {session_handler}; | ||
| 105 | is_domain = true; | ||
| 106 | } | ||
| 107 | |||
| 108 | std::size_t DomainHandlerCount() const { | ||
| 109 | return domain_handlers.size(); | ||
| 110 | } | ||
| 111 | |||
| 112 | bool HasSessionHandler() const { | ||
| 113 | return session_handler != nullptr; | ||
| 114 | } | ||
| 115 | |||
| 116 | SessionRequestHandler& SessionHandler() { | ||
| 117 | return *session_handler; | ||
| 118 | } | ||
| 119 | |||
| 120 | const SessionRequestHandler& SessionHandler() const { | ||
| 121 | return *session_handler; | ||
| 122 | } | ||
| 123 | |||
| 124 | void CloseDomainHandler(std::size_t index) { | ||
| 125 | if (index < DomainHandlerCount()) { | ||
| 126 | domain_handlers[index] = nullptr; | ||
| 127 | } else { | ||
| 128 | UNREACHABLE_MSG("Unexpected handler index {}", index); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | SessionRequestHandlerPtr DomainHandler(std::size_t index) const { | ||
| 133 | ASSERT_MSG(index < DomainHandlerCount(), "Unexpected handler index {}", index); | ||
| 134 | return domain_handlers.at(index); | ||
| 135 | } | ||
| 136 | |||
| 137 | void AppendDomainHandler(SessionRequestHandlerPtr&& handler) { | ||
| 138 | domain_handlers.emplace_back(std::move(handler)); | ||
| 139 | } | ||
| 140 | |||
| 141 | void SetSessionHandler(SessionRequestHandlerPtr&& handler) { | ||
| 142 | session_handler = std::move(handler); | ||
| 143 | } | ||
| 144 | |||
| 145 | private: | ||
| 146 | bool is_domain{}; | ||
| 147 | SessionRequestHandlerPtr session_handler; | ||
| 148 | std::vector<SessionRequestHandlerPtr> domain_handlers; | ||
| 149 | }; | ||
| 150 | |||
| 87 | /** | 151 | /** |
| 88 | * Class containing information about an in-flight IPC request being handled by an HLE service | 152 | * Class containing information about an in-flight IPC request being handled by an HLE service |
| 89 | * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and | 153 | * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and |
| @@ -224,53 +288,32 @@ public: | |||
| 224 | bool CanWriteBuffer(std::size_t buffer_index = 0) const; | 288 | bool CanWriteBuffer(std::size_t buffer_index = 0) const; |
| 225 | 289 | ||
| 226 | Handle GetCopyHandle(std::size_t index) const { | 290 | Handle GetCopyHandle(std::size_t index) const { |
| 227 | return copy_handles.at(index); | 291 | return incoming_copy_handles.at(index); |
| 228 | } | 292 | } |
| 229 | 293 | ||
| 230 | Handle GetMoveHandle(std::size_t index) const { | 294 | Handle GetMoveHandle(std::size_t index) const { |
| 231 | return move_handles.at(index); | 295 | return incoming_move_handles.at(index); |
| 232 | } | 296 | } |
| 233 | 297 | ||
| 234 | void AddMoveObject(KAutoObject* object) { | 298 | void AddMoveObject(KAutoObject* object) { |
| 235 | move_objects.emplace_back(object); | 299 | outgoing_move_objects.emplace_back(object); |
| 236 | } | 300 | } |
| 237 | 301 | ||
| 238 | void AddCopyObject(KAutoObject* object) { | 302 | void AddCopyObject(KAutoObject* object) { |
| 239 | copy_objects.emplace_back(object); | 303 | outgoing_copy_objects.emplace_back(object); |
| 240 | } | 304 | } |
| 241 | 305 | ||
| 242 | void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { | 306 | void AddDomainObject(SessionRequestHandlerPtr object) { |
| 243 | domain_objects.emplace_back(std::move(object)); | 307 | outgoing_domain_objects.emplace_back(std::move(object)); |
| 244 | } | 308 | } |
| 245 | 309 | ||
| 246 | template <typename T> | 310 | template <typename T> |
| 247 | std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const { | 311 | std::shared_ptr<T> GetDomainHandler(std::size_t index) const { |
| 248 | return std::static_pointer_cast<T>(domain_request_handlers.at(index)); | 312 | return std::static_pointer_cast<T>(manager->DomainHandler(index)); |
| 249 | } | ||
| 250 | |||
| 251 | void SetDomainRequestHandlers( | ||
| 252 | const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) { | ||
| 253 | domain_request_handlers = handlers; | ||
| 254 | } | ||
| 255 | |||
| 256 | /// Clears the list of objects so that no lingering objects are written accidentally to the | ||
| 257 | /// response buffer. | ||
| 258 | void ClearIncomingObjects() { | ||
| 259 | move_objects.clear(); | ||
| 260 | copy_objects.clear(); | ||
| 261 | domain_objects.clear(); | ||
| 262 | } | 313 | } |
| 263 | 314 | ||
| 264 | std::size_t NumMoveObjects() const { | 315 | void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { |
| 265 | return move_objects.size(); | 316 | manager = std::move(manager_); |
| 266 | } | ||
| 267 | |||
| 268 | std::size_t NumCopyObjects() const { | ||
| 269 | return copy_objects.size(); | ||
| 270 | } | ||
| 271 | |||
| 272 | std::size_t NumDomainObjects() const { | ||
| 273 | return domain_objects.size(); | ||
| 274 | } | 317 | } |
| 275 | 318 | ||
| 276 | std::string Description() const; | 319 | std::string Description() const; |
| @@ -292,12 +335,12 @@ private: | |||
| 292 | Kernel::KServerSession* server_session{}; | 335 | Kernel::KServerSession* server_session{}; |
| 293 | KThread* thread; | 336 | KThread* thread; |
| 294 | 337 | ||
| 295 | // TODO(yuriks): Check common usage of this and optimize size accordingly | 338 | std::vector<Handle> incoming_move_handles; |
| 296 | boost::container::small_vector<Handle, 8> move_handles; | 339 | std::vector<Handle> incoming_copy_handles; |
| 297 | boost::container::small_vector<Handle, 8> copy_handles; | 340 | |
| 298 | boost::container::small_vector<KAutoObject*, 8> move_objects; | 341 | std::vector<KAutoObject*> outgoing_move_objects; |
| 299 | boost::container::small_vector<KAutoObject*, 8> copy_objects; | 342 | std::vector<KAutoObject*> outgoing_copy_objects; |
| 300 | boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; | 343 | std::vector<SessionRequestHandlerPtr> outgoing_domain_objects; |
| 301 | 344 | ||
| 302 | std::optional<IPC::CommandHeader> command_header; | 345 | std::optional<IPC::CommandHeader> command_header; |
| 303 | std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; | 346 | std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; |
| @@ -311,12 +354,12 @@ private: | |||
| 311 | 354 | ||
| 312 | u32_le command{}; | 355 | u32_le command{}; |
| 313 | u64 pid{}; | 356 | u64 pid{}; |
| 357 | u32 write_size{}; | ||
| 314 | u32 data_payload_offset{}; | 358 | u32 data_payload_offset{}; |
| 315 | u32 handles_offset{}; | 359 | u32 handles_offset{}; |
| 316 | u32 domain_offset{}; | 360 | u32 domain_offset{}; |
| 317 | u32 data_size{}; | ||
| 318 | 361 | ||
| 319 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; | 362 | std::shared_ptr<SessionRequestManager> manager; |
| 320 | bool is_thread_waiting{}; | 363 | bool is_thread_waiting{}; |
| 321 | 364 | ||
| 322 | KernelCore& kernel; | 365 | KernelCore& kernel; |
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 69ae405e6..10edede17 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp | |||
| @@ -70,14 +70,22 @@ constexpr size_t SlabCountExtraKThread = 160; | |||
| 70 | template <typename T> | 70 | template <typename T> |
| 71 | VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, | 71 | VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, |
| 72 | size_t num_objects) { | 72 | size_t num_objects) { |
| 73 | // TODO(bunnei): This is just a place holder. We should initialize the appropriate KSlabHeap for | ||
| 74 | // kernel object type T with the backing kernel memory pointer once we emulate kernel memory. | ||
| 75 | |||
| 73 | const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*)); | 76 | const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*)); |
| 74 | VAddr start = Common::AlignUp(address, alignof(T)); | 77 | VAddr start = Common::AlignUp(address, alignof(T)); |
| 75 | 78 | ||
| 79 | // This is intentionally empty. Once KSlabHeap is fully implemented, we can replace this with | ||
| 80 | // the pointer to emulated memory to pass along. Until then, KSlabHeap will just allocate/free | ||
| 81 | // host memory. | ||
| 82 | void* backing_kernel_memory{}; | ||
| 83 | |||
| 76 | if (size > 0) { | 84 | if (size > 0) { |
| 77 | const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1); | 85 | const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1); |
| 78 | ASSERT(region != nullptr); | 86 | ASSERT(region != nullptr); |
| 79 | ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); | 87 | ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); |
| 80 | T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size); | 88 | T::InitializeSlabHeap(system.Kernel(), backing_kernel_memory, size); |
| 81 | } | 89 | } |
| 82 | 90 | ||
| 83 | return start + size; | 91 | return start + size; |
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index ad01cf67e..4a12dee10 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp | |||
| @@ -58,9 +58,9 @@ bool KClientPort::IsSignaled() const { | |||
| 58 | 58 | ||
| 59 | ResultCode KClientPort::CreateSession(KClientSession** out) { | 59 | ResultCode KClientPort::CreateSession(KClientSession** out) { |
| 60 | // Reserve a new session from the resource limit. | 60 | // Reserve a new session from the resource limit. |
| 61 | // KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), | 61 | KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), |
| 62 | // LimitableResource::Sessions); | 62 | LimitableResource::Sessions); |
| 63 | // R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); | 63 | R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); |
| 64 | 64 | ||
| 65 | // Update the session counts. | 65 | // Update the session counts. |
| 66 | { | 66 | { |
| @@ -104,7 +104,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) { | |||
| 104 | session->Initialize(this, parent->GetName()); | 104 | session->Initialize(this, parent->GetName()); |
| 105 | 105 | ||
| 106 | // Commit the session reservation. | 106 | // Commit the session reservation. |
| 107 | // session_reservation.Commit(); | 107 | session_reservation.Commit(); |
| 108 | 108 | ||
| 109 | // Register the session. | 109 | // Register the session. |
| 110 | KSession::Register(kernel, session); | 110 | KSession::Register(kernel, session); |
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index d00ce3ddd..8501156e8 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h | |||
| @@ -31,6 +31,9 @@ public: | |||
| 31 | const KPort* GetParent() const { | 31 | const KPort* GetParent() const { |
| 32 | return parent; | 32 | return parent; |
| 33 | } | 33 | } |
| 34 | KPort* GetParent() { | ||
| 35 | return parent; | ||
| 36 | } | ||
| 34 | 37 | ||
| 35 | s32 GetNumSessions() const { | 38 | s32 GetNumSessions() const { |
| 36 | return num_sessions; | 39 | return num_sessions; |
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index feb2bb11f..223c0b205 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp | |||
| @@ -56,11 +56,8 @@ ResultCode KPort::EnqueueSession(KServerSession* session) { | |||
| 56 | 56 | ||
| 57 | R_UNLESS(state == State::Normal, ResultPortClosed); | 57 | R_UNLESS(state == State::Normal, ResultPortClosed); |
| 58 | 58 | ||
| 59 | if (server.HasHLEHandler()) { | 59 | server.EnqueueSession(session); |
| 60 | server.GetHLEHandler()->ClientConnected(session); | 60 | server.GetSessionRequestHandler()->ClientConnected(server.AcceptSession()); |
| 61 | } else { | ||
| 62 | server.EnqueueSession(session); | ||
| 63 | } | ||
| 64 | 61 | ||
| 65 | return RESULT_SUCCESS; | 62 | return RESULT_SUCCESS; |
| 66 | } | 63 | } |
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index e76792253..d1a757ec3 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h | |||
| @@ -32,26 +32,24 @@ public: | |||
| 32 | explicit KServerPort(KernelCore& kernel_); | 32 | explicit KServerPort(KernelCore& kernel_); |
| 33 | virtual ~KServerPort() override; | 33 | virtual ~KServerPort() override; |
| 34 | 34 | ||
| 35 | using HLEHandler = std::shared_ptr<SessionRequestHandler>; | ||
| 36 | |||
| 37 | void Initialize(KPort* parent_, std::string&& name_); | 35 | void Initialize(KPort* parent_, std::string&& name_); |
| 38 | 36 | ||
| 39 | /// Whether or not this server port has an HLE handler available. | 37 | /// Whether or not this server port has an HLE handler available. |
| 40 | bool HasHLEHandler() const { | 38 | bool HasSessionRequestHandler() const { |
| 41 | return hle_handler != nullptr; | 39 | return session_handler != nullptr; |
| 42 | } | 40 | } |
| 43 | 41 | ||
| 44 | /// Gets the HLE handler for this port. | 42 | /// Gets the HLE handler for this port. |
| 45 | HLEHandler GetHLEHandler() const { | 43 | SessionRequestHandlerPtr GetSessionRequestHandler() const { |
| 46 | return hle_handler; | 44 | return session_handler; |
| 47 | } | 45 | } |
| 48 | 46 | ||
| 49 | /** | 47 | /** |
| 50 | * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port | 48 | * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port |
| 51 | * will inherit a reference to this handler. | 49 | * will inherit a reference to this handler. |
| 52 | */ | 50 | */ |
| 53 | void SetHleHandler(HLEHandler hle_handler_) { | 51 | void SetSessionHandler(SessionRequestHandlerPtr&& handler) { |
| 54 | hle_handler = std::move(hle_handler_); | 52 | session_handler = std::move(handler); |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 57 | void EnqueueSession(KServerSession* pending_session); | 55 | void EnqueueSession(KServerSession* pending_session); |
| @@ -73,7 +71,7 @@ private: | |||
| 73 | 71 | ||
| 74 | private: | 72 | private: |
| 75 | SessionList session_list; | 73 | SessionList session_list; |
| 76 | HLEHandler hle_handler; | 74 | SessionRequestHandlerPtr session_handler; |
| 77 | KPort* parent{}; | 75 | KPort* parent{}; |
| 78 | }; | 76 | }; |
| 79 | 77 | ||
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 8850d9af5..457fdfd60 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -23,7 +23,8 @@ | |||
| 23 | 23 | ||
| 24 | namespace Kernel { | 24 | namespace Kernel { |
| 25 | 25 | ||
| 26 | KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} | 26 | KServerSession::KServerSession(KernelCore& kernel_) |
| 27 | : KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {} | ||
| 27 | 28 | ||
| 28 | KServerSession::~KServerSession() { | 29 | KServerSession::~KServerSession() { |
| 29 | kernel.ReleaseServiceThread(service_thread); | 30 | kernel.ReleaseServiceThread(service_thread); |
| @@ -43,14 +44,8 @@ void KServerSession::Destroy() { | |||
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | void KServerSession::OnClientClosed() { | 46 | void KServerSession::OnClientClosed() { |
| 46 | // We keep a shared pointer to the hle handler to keep it alive throughout | 47 | if (manager->HasSessionHandler()) { |
| 47 | // the call to ClientDisconnected, as ClientDisconnected invalidates the | 48 | manager->SessionHandler().ClientDisconnected(this); |
| 48 | // hle_handler member itself during the course of the function executing. | ||
| 49 | std::shared_ptr<SessionRequestHandler> handler = hle_handler; | ||
| 50 | if (handler) { | ||
| 51 | // Note that after this returns, this server session's hle_handler is | ||
| 52 | // invalidated (set to null). | ||
| 53 | handler->ClientDisconnected(this); | ||
| 54 | } | 49 | } |
| 55 | } | 50 | } |
| 56 | 51 | ||
| @@ -66,12 +61,12 @@ bool KServerSession::IsSignaled() const { | |||
| 66 | return false; | 61 | return false; |
| 67 | } | 62 | } |
| 68 | 63 | ||
| 69 | void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { | 64 | void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { |
| 70 | domain_request_handlers.push_back(std::move(handler)); | 65 | manager->AppendDomainHandler(std::move(handler)); |
| 71 | } | 66 | } |
| 72 | 67 | ||
| 73 | std::size_t KServerSession::NumDomainRequestHandlers() const { | 68 | std::size_t KServerSession::NumDomainRequestHandlers() const { |
| 74 | return domain_request_handlers.size(); | 69 | return manager->DomainHandlerCount(); |
| 75 | } | 70 | } |
| 76 | 71 | ||
| 77 | ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { | 72 | ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { |
| @@ -80,14 +75,14 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co | |||
| 80 | } | 75 | } |
| 81 | 76 | ||
| 82 | // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs | 77 | // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs |
| 83 | context.SetDomainRequestHandlers(domain_request_handlers); | 78 | context.SetSessionRequestManager(manager); |
| 84 | 79 | ||
| 85 | // If there is a DomainMessageHeader, then this is CommandType "Request" | 80 | // If there is a DomainMessageHeader, then this is CommandType "Request" |
| 86 | const auto& domain_message_header = context.GetDomainMessageHeader(); | 81 | const auto& domain_message_header = context.GetDomainMessageHeader(); |
| 87 | const u32 object_id{domain_message_header.object_id}; | 82 | const u32 object_id{domain_message_header.object_id}; |
| 88 | switch (domain_message_header.command) { | 83 | switch (domain_message_header.command) { |
| 89 | case IPC::DomainMessageHeader::CommandType::SendMessage: | 84 | case IPC::DomainMessageHeader::CommandType::SendMessage: |
| 90 | if (object_id > domain_request_handlers.size()) { | 85 | if (object_id > manager->DomainHandlerCount()) { |
| 91 | LOG_CRITICAL(IPC, | 86 | LOG_CRITICAL(IPC, |
| 92 | "object_id {} is too big! This probably means a recent service call " | 87 | "object_id {} is too big! This probably means a recent service call " |
| 93 | "to {} needed to return a new interface!", | 88 | "to {} needed to return a new interface!", |
| @@ -95,12 +90,12 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co | |||
| 95 | UNREACHABLE(); | 90 | UNREACHABLE(); |
| 96 | return RESULT_SUCCESS; // Ignore error if asserts are off | 91 | return RESULT_SUCCESS; // Ignore error if asserts are off |
| 97 | } | 92 | } |
| 98 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context); | 93 | return manager->DomainHandler(object_id - 1)->HandleSyncRequest(*this, context); |
| 99 | 94 | ||
| 100 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | 95 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { |
| 101 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); | 96 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); |
| 102 | 97 | ||
| 103 | domain_request_handlers[object_id - 1] = nullptr; | 98 | manager->CloseDomainHandler(object_id - 1); |
| 104 | 99 | ||
| 105 | IPC::ResponseBuilder rb{context, 2}; | 100 | IPC::ResponseBuilder rb{context, 2}; |
| 106 | rb.Push(RESULT_SUCCESS); | 101 | rb.Push(RESULT_SUCCESS); |
| @@ -133,14 +128,14 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 133 | if (IsDomain() && context.HasDomainMessageHeader()) { | 128 | if (IsDomain() && context.HasDomainMessageHeader()) { |
| 134 | result = HandleDomainSyncRequest(context); | 129 | result = HandleDomainSyncRequest(context); |
| 135 | // If there is no domain header, the regular session handler is used | 130 | // If there is no domain header, the regular session handler is used |
| 136 | } else if (hle_handler != nullptr) { | 131 | } else if (manager->HasSessionHandler()) { |
| 137 | // If this ServerSession has an associated HLE handler, forward the request to it. | 132 | // If this ServerSession has an associated HLE handler, forward the request to it. |
| 138 | result = hle_handler->HandleSyncRequest(*this, context); | 133 | result = manager->SessionHandler().HandleSyncRequest(*this, context); |
| 139 | } | 134 | } |
| 140 | 135 | ||
| 141 | if (convert_to_domain) { | 136 | if (convert_to_domain) { |
| 142 | ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); | 137 | ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); |
| 143 | domain_request_handlers = {hle_handler}; | 138 | manager->ConvertToDomain(); |
| 144 | convert_to_domain = false; | 139 | convert_to_domain = false; |
| 145 | } | 140 | } |
| 146 | 141 | ||
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 597d76d38..dd4de2904 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <boost/intrusive/list.hpp> | 12 | #include <boost/intrusive/list.hpp> |
| 13 | 13 | ||
| 14 | #include "common/threadsafe_queue.h" | 14 | #include "common/threadsafe_queue.h" |
| 15 | #include "core/hle/kernel/hle_ipc.h" | ||
| 15 | #include "core/hle/kernel/k_synchronization_object.h" | 16 | #include "core/hle/kernel/k_synchronization_object.h" |
| 16 | #include "core/hle/kernel/service_thread.h" | 17 | #include "core/hle/kernel/service_thread.h" |
| 17 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| @@ -64,8 +65,8 @@ public: | |||
| 64 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not | 65 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not |
| 65 | * implemented.) | 66 | * implemented.) |
| 66 | */ | 67 | */ |
| 67 | void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) { | 68 | void SetSessionHandler(SessionRequestHandlerPtr handler) { |
| 68 | hle_handler = std::move(hle_handler_); | 69 | manager->SetSessionHandler(std::move(handler)); |
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | /** | 72 | /** |
| @@ -82,7 +83,7 @@ public: | |||
| 82 | 83 | ||
| 83 | /// Adds a new domain request handler to the collection of request handlers within | 84 | /// Adds a new domain request handler to the collection of request handlers within |
| 84 | /// this ServerSession instance. | 85 | /// this ServerSession instance. |
| 85 | void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); | 86 | void AppendDomainHandler(SessionRequestHandlerPtr handler); |
| 86 | 87 | ||
| 87 | /// Retrieves the total number of domain request handlers that have been | 88 | /// Retrieves the total number of domain request handlers that have been |
| 88 | /// appended to this ServerSession instance. | 89 | /// appended to this ServerSession instance. |
| @@ -90,12 +91,7 @@ public: | |||
| 90 | 91 | ||
| 91 | /// Returns true if the session has been converted to a domain, otherwise False | 92 | /// Returns true if the session has been converted to a domain, otherwise False |
| 92 | bool IsDomain() const { | 93 | bool IsDomain() const { |
| 93 | return !IsSession(); | 94 | return manager->IsDomain(); |
| 94 | } | ||
| 95 | |||
| 96 | /// Returns true if this session has not been converted to a domain, otherwise false. | ||
| 97 | bool IsSession() const { | ||
| 98 | return domain_request_handlers.empty(); | ||
| 99 | } | 95 | } |
| 100 | 96 | ||
| 101 | /// Converts the session to a domain at the end of the current command | 97 | /// Converts the session to a domain at the end of the current command |
| @@ -103,6 +99,21 @@ public: | |||
| 103 | convert_to_domain = true; | 99 | convert_to_domain = true; |
| 104 | } | 100 | } |
| 105 | 101 | ||
| 102 | /// Gets the session request manager, which forwards requests to the underlying service | ||
| 103 | std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { | ||
| 104 | return manager; | ||
| 105 | } | ||
| 106 | |||
| 107 | /// Gets the session request manager, which forwards requests to the underlying service | ||
| 108 | const std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() const { | ||
| 109 | return manager; | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Sets the session request manager, which forwards requests to the underlying service | ||
| 113 | void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { | ||
| 114 | manager = std::move(manager_); | ||
| 115 | } | ||
| 116 | |||
| 106 | private: | 117 | private: |
| 107 | /// Queues a sync request from the emulated application. | 118 | /// Queues a sync request from the emulated application. |
| 108 | ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); | 119 | ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); |
| @@ -114,11 +125,8 @@ private: | |||
| 114 | /// object handle. | 125 | /// object handle. |
| 115 | ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); | 126 | ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); |
| 116 | 127 | ||
| 117 | /// This session's HLE request handler (applicable when not a domain) | 128 | /// This session's HLE request handlers |
| 118 | std::shared_ptr<SessionRequestHandler> hle_handler; | 129 | std::shared_ptr<SessionRequestManager> manager; |
| 119 | |||
| 120 | /// This is the list of domain request handlers (after conversion to a domain) | ||
| 121 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; | ||
| 122 | 130 | ||
| 123 | /// When set to True, converts the session to a domain at the end of the command | 131 | /// When set to True, converts the session to a domain at the end of the command |
| 124 | bool convert_to_domain{}; | 132 | bool convert_to_domain{}; |
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index b7ce27a0b..025b8b555 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp | |||
| @@ -78,7 +78,7 @@ void KSession::OnClientClosed() { | |||
| 78 | void KSession::PostDestroy(uintptr_t arg) { | 78 | void KSession::PostDestroy(uintptr_t arg) { |
| 79 | // Release the session count resource the owner process holds. | 79 | // Release the session count resource the owner process holds. |
| 80 | KProcess* owner = reinterpret_cast<KProcess*>(arg); | 80 | KProcess* owner = reinterpret_cast<KProcess*>(arg); |
| 81 | // owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); | 81 | owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); |
| 82 | owner->Close(); | 82 | owner->Close(); |
| 83 | } | 83 | } |
| 84 | 84 | ||
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 16901e19c..a981fd1f6 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h | |||
| @@ -66,6 +66,10 @@ public: | |||
| 66 | return port; | 66 | return port; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | KClientPort* GetParent() { | ||
| 70 | return port; | ||
| 71 | } | ||
| 72 | |||
| 69 | private: | 73 | private: |
| 70 | enum class State : u8 { | 74 | enum class State : u8 { |
| 71 | Invalid = 0, | 75 | Invalid = 0, |
diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index 5ce9a1d7c..81d472a3e 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h | |||
| @@ -4,165 +4,33 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Kernel { | 7 | namespace Kernel { |
| 13 | 8 | ||
| 14 | namespace impl { | 9 | class KernelCore; |
| 15 | |||
| 16 | class KSlabHeapImpl final : NonCopyable { | ||
| 17 | public: | ||
| 18 | struct Node { | ||
| 19 | Node* next{}; | ||
| 20 | }; | ||
| 21 | |||
| 22 | constexpr KSlabHeapImpl() = default; | ||
| 23 | |||
| 24 | void Initialize(std::size_t size) { | ||
| 25 | ASSERT(head == nullptr); | ||
| 26 | obj_size = size; | ||
| 27 | } | ||
| 28 | |||
| 29 | constexpr std::size_t GetObjectSize() const { | ||
| 30 | return obj_size; | ||
| 31 | } | ||
| 32 | |||
| 33 | Node* GetHead() const { | ||
| 34 | return head; | ||
| 35 | } | ||
| 36 | |||
| 37 | void* Allocate() { | ||
| 38 | Node* ret = head.load(); | ||
| 39 | |||
| 40 | do { | ||
| 41 | if (ret == nullptr) { | ||
| 42 | break; | ||
| 43 | } | ||
| 44 | } while (!head.compare_exchange_weak(ret, ret->next)); | ||
| 45 | |||
| 46 | return ret; | ||
| 47 | } | ||
| 48 | |||
| 49 | void Free(void* obj) { | ||
| 50 | Node* node = static_cast<Node*>(obj); | ||
| 51 | |||
| 52 | Node* cur_head = head.load(); | ||
| 53 | do { | ||
| 54 | node->next = cur_head; | ||
| 55 | } while (!head.compare_exchange_weak(cur_head, node)); | ||
| 56 | } | ||
| 57 | |||
| 58 | private: | ||
| 59 | std::atomic<Node*> head{}; | ||
| 60 | std::size_t obj_size{}; | ||
| 61 | }; | ||
| 62 | |||
| 63 | } // namespace impl | ||
| 64 | |||
| 65 | class KSlabHeapBase : NonCopyable { | ||
| 66 | public: | ||
| 67 | constexpr KSlabHeapBase() = default; | ||
| 68 | |||
| 69 | constexpr bool Contains(uintptr_t addr) const { | ||
| 70 | return start <= addr && addr < end; | ||
| 71 | } | ||
| 72 | |||
| 73 | constexpr std::size_t GetSlabHeapSize() const { | ||
| 74 | return (end - start) / GetObjectSize(); | ||
| 75 | } | ||
| 76 | |||
| 77 | constexpr std::size_t GetObjectSize() const { | ||
| 78 | return impl.GetObjectSize(); | ||
| 79 | } | ||
| 80 | 10 | ||
| 81 | constexpr uintptr_t GetSlabHeapAddress() const { | 11 | /// This is a placeholder class to manage slab heaps for kernel objects. For now, we just allocate |
| 82 | return start; | 12 | /// these with new/delete, but this can be re-implemented later to allocate these in emulated |
| 83 | } | 13 | /// memory. |
| 84 | |||
| 85 | std::size_t GetObjectIndexImpl(const void* obj) const { | ||
| 86 | return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize(); | ||
| 87 | } | ||
| 88 | |||
| 89 | std::size_t GetPeakIndex() const { | ||
| 90 | return GetObjectIndexImpl(reinterpret_cast<const void*>(peak)); | ||
| 91 | } | ||
| 92 | |||
| 93 | void* AllocateImpl() { | ||
| 94 | return impl.Allocate(); | ||
| 95 | } | ||
| 96 | |||
| 97 | void FreeImpl(void* obj) { | ||
| 98 | // Don't allow freeing an object that wasn't allocated from this heap | ||
| 99 | ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); | ||
| 100 | |||
| 101 | impl.Free(obj); | ||
| 102 | } | ||
| 103 | |||
| 104 | void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { | ||
| 105 | // Ensure we don't initialize a slab using null memory | ||
| 106 | ASSERT(memory != nullptr); | ||
| 107 | |||
| 108 | // Initialize the base allocator | ||
| 109 | impl.Initialize(obj_size); | ||
| 110 | |||
| 111 | // Set our tracking variables | ||
| 112 | const std::size_t num_obj = (memory_size / obj_size); | ||
| 113 | start = reinterpret_cast<uintptr_t>(memory); | ||
| 114 | end = start + num_obj * obj_size; | ||
| 115 | peak = start; | ||
| 116 | |||
| 117 | // Free the objects | ||
| 118 | u8* cur = reinterpret_cast<u8*>(end); | ||
| 119 | |||
| 120 | for (std::size_t i{}; i < num_obj; i++) { | ||
| 121 | cur -= obj_size; | ||
| 122 | impl.Free(cur); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | private: | ||
| 127 | using Impl = impl::KSlabHeapImpl; | ||
| 128 | |||
| 129 | Impl impl; | ||
| 130 | uintptr_t peak{}; | ||
| 131 | uintptr_t start{}; | ||
| 132 | uintptr_t end{}; | ||
| 133 | }; | ||
| 134 | 14 | ||
| 135 | template <typename T> | 15 | template <typename T> |
| 136 | class KSlabHeap final : public KSlabHeapBase { | 16 | class KSlabHeap final : NonCopyable { |
| 137 | public: | 17 | public: |
| 138 | constexpr KSlabHeap() : KSlabHeapBase() {} | 18 | KSlabHeap() = default; |
| 139 | 19 | ||
| 140 | void Initialize(void* memory, std::size_t memory_size) { | 20 | void Initialize([[maybe_unused]] void* memory, [[maybe_unused]] std::size_t memory_size) { |
| 141 | InitializeImpl(sizeof(T), memory, memory_size); | 21 | // Placeholder that should initialize the backing slab heap implementation. |
| 142 | } | 22 | } |
| 143 | 23 | ||
| 144 | T* Allocate() { | 24 | T* Allocate() { |
| 145 | T* obj = static_cast<T*>(AllocateImpl()); | 25 | return new T(); |
| 146 | if (obj != nullptr) { | ||
| 147 | new (obj) T(); | ||
| 148 | } | ||
| 149 | return obj; | ||
| 150 | } | 26 | } |
| 151 | 27 | ||
| 152 | T* AllocateWithKernel(KernelCore& kernel) { | 28 | T* AllocateWithKernel(KernelCore& kernel) { |
| 153 | T* obj = static_cast<T*>(AllocateImpl()); | 29 | return new T(kernel); |
| 154 | if (obj != nullptr) { | ||
| 155 | new (obj) T(kernel); | ||
| 156 | } | ||
| 157 | return obj; | ||
| 158 | } | 30 | } |
| 159 | 31 | ||
| 160 | void Free(T* obj) { | 32 | void Free(T* obj) { |
| 161 | FreeImpl(obj); | 33 | delete obj; |
| 162 | } | ||
| 163 | |||
| 164 | constexpr std::size_t GetObjectIndex(const T* obj) const { | ||
| 165 | return GetObjectIndexImpl(obj); | ||
| 166 | } | 34 | } |
| 167 | }; | 35 | }; |
| 168 | 36 | ||
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index fcb8b1ea5..b2ceeceb3 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp | |||
| @@ -22,6 +22,7 @@ enum : u32 { | |||
| 22 | CapabilityOffset_Syscall = 4, | 22 | CapabilityOffset_Syscall = 4, |
| 23 | CapabilityOffset_MapPhysical = 6, | 23 | CapabilityOffset_MapPhysical = 6, |
| 24 | CapabilityOffset_MapIO = 7, | 24 | CapabilityOffset_MapIO = 7, |
| 25 | CapabilityOffset_MapRegion = 10, | ||
| 25 | CapabilityOffset_Interrupt = 11, | 26 | CapabilityOffset_Interrupt = 11, |
| 26 | CapabilityOffset_ProgramType = 13, | 27 | CapabilityOffset_ProgramType = 13, |
| 27 | CapabilityOffset_KernelVersion = 14, | 28 | CapabilityOffset_KernelVersion = 14, |
| @@ -46,6 +47,7 @@ enum class CapabilityType : u32 { | |||
| 46 | Syscall = (1U << CapabilityOffset_Syscall) - 1, | 47 | Syscall = (1U << CapabilityOffset_Syscall) - 1, |
| 47 | MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1, | 48 | MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1, |
| 48 | MapIO = (1U << CapabilityOffset_MapIO) - 1, | 49 | MapIO = (1U << CapabilityOffset_MapIO) - 1, |
| 50 | MapRegion = (1U << CapabilityOffset_MapRegion) - 1, | ||
| 49 | Interrupt = (1U << CapabilityOffset_Interrupt) - 1, | 51 | Interrupt = (1U << CapabilityOffset_Interrupt) - 1, |
| 50 | ProgramType = (1U << CapabilityOffset_ProgramType) - 1, | 52 | ProgramType = (1U << CapabilityOffset_ProgramType) - 1, |
| 51 | KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1, | 53 | KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1, |
| @@ -187,6 +189,8 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s | |||
| 187 | return HandleSyscallFlags(set_svc_bits, flag); | 189 | return HandleSyscallFlags(set_svc_bits, flag); |
| 188 | case CapabilityType::MapIO: | 190 | case CapabilityType::MapIO: |
| 189 | return HandleMapIOFlags(flag, page_table); | 191 | return HandleMapIOFlags(flag, page_table); |
| 192 | case CapabilityType::MapRegion: | ||
| 193 | return HandleMapRegionFlags(flag, page_table); | ||
| 190 | case CapabilityType::Interrupt: | 194 | case CapabilityType::Interrupt: |
| 191 | return HandleInterruptFlags(flag); | 195 | return HandleInterruptFlags(flag); |
| 192 | case CapabilityType::ProgramType: | 196 | case CapabilityType::ProgramType: |
| @@ -298,6 +302,11 @@ ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, KPageTable& page_tab | |||
| 298 | return RESULT_SUCCESS; | 302 | return RESULT_SUCCESS; |
| 299 | } | 303 | } |
| 300 | 304 | ||
| 305 | ResultCode ProcessCapabilities::HandleMapRegionFlags(u32 flags, KPageTable& page_table) { | ||
| 306 | // TODO(Lioncache): Implement once the memory manager can handle this. | ||
| 307 | return RESULT_SUCCESS; | ||
| 308 | } | ||
| 309 | |||
| 301 | ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) { | 310 | ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) { |
| 302 | constexpr u32 interrupt_ignore_value = 0x3FF; | 311 | constexpr u32 interrupt_ignore_value = 0x3FF; |
| 303 | const u32 interrupt0 = (flags >> 12) & 0x3FF; | 312 | const u32 interrupt0 = (flags >> 12) & 0x3FF; |
diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h index b7a9b2e45..2a7bf5505 100644 --- a/src/core/hle/kernel/process_capability.h +++ b/src/core/hle/kernel/process_capability.h | |||
| @@ -231,6 +231,9 @@ private: | |||
| 231 | /// Handles flags related to mapping IO pages. | 231 | /// Handles flags related to mapping IO pages. |
| 232 | ResultCode HandleMapIOFlags(u32 flags, KPageTable& page_table); | 232 | ResultCode HandleMapIOFlags(u32 flags, KPageTable& page_table); |
| 233 | 233 | ||
| 234 | /// Handles flags related to mapping physical memory regions. | ||
| 235 | ResultCode HandleMapRegionFlags(u32 flags, KPageTable& page_table); | ||
| 236 | |||
| 234 | /// Handles flags related to the interrupt capability flags. | 237 | /// Handles flags related to the interrupt capability flags. |
| 235 | ResultCode HandleInterruptFlags(u32 flags); | 238 | ResultCode HandleInterruptFlags(u32 flags); |
| 236 | 239 | ||
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 04be8a502..2ae80beca 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp | |||
| @@ -74,21 +74,17 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session, | |||
| 74 | { | 74 | { |
| 75 | std::unique_lock lock{queue_mutex}; | 75 | std::unique_lock lock{queue_mutex}; |
| 76 | 76 | ||
| 77 | auto* server_session{&session.GetServerSession()}; | ||
| 78 | |||
| 77 | // Open a reference to the session to ensure it is not closes while the service request | 79 | // Open a reference to the session to ensure it is not closes while the service request |
| 78 | // completes asynchronously. | 80 | // completes asynchronously. |
| 79 | session.Open(); | 81 | server_session->Open(); |
| 80 | 82 | ||
| 81 | requests.emplace([session_ptr{&session}, context{std::move(context)}]() { | 83 | requests.emplace([server_session, context{std::move(context)}]() { |
| 82 | // Close the reference. | 84 | // Close the reference. |
| 83 | SCOPE_EXIT({ session_ptr->Close(); }); | 85 | SCOPE_EXIT({ server_session->Close(); }); |
| 84 | |||
| 85 | // If the session has been closed, we are done. | ||
| 86 | if (session_ptr->IsServerClosed()) { | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | 86 | ||
| 90 | // Complete the service request. | 87 | // Complete the service request. |
| 91 | KScopedAutoObject server_session{&session_ptr->GetServerSession()}; | ||
| 92 | server_session->CompleteSyncRequest(*context); | 88 | server_session->CompleteSyncRequest(*context); |
| 93 | }); | 89 | }); |
| 94 | } | 90 | } |
diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index d0f7f084b..0c5995db0 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h | |||
| @@ -67,11 +67,11 @@ class KAutoObjectWithSlabHeapAndContainer : public Base { | |||
| 67 | 67 | ||
| 68 | private: | 68 | private: |
| 69 | static Derived* Allocate(KernelCore& kernel) { | 69 | static Derived* Allocate(KernelCore& kernel) { |
| 70 | return new Derived(kernel); | 70 | return kernel.SlabHeap<Derived>().AllocateWithKernel(kernel); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static void Free(KernelCore& kernel, Derived* obj) { | 73 | static void Free(KernelCore& kernel, Derived* obj) { |
| 74 | delete obj; | 74 | kernel.SlabHeap<Derived>().Free(obj); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | public: | 77 | public: |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 2c9b2ce6d..fa61a5c7b 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -107,7 +107,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) | |||
| 107 | ASSERT(!port_installed); | 107 | ASSERT(!port_installed); |
| 108 | 108 | ||
| 109 | auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); | 109 | auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); |
| 110 | port->SetHleHandler(shared_from_this()); | 110 | port->SetSessionHandler(shared_from_this()); |
| 111 | port_installed = true; | 111 | port_installed = true; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| @@ -118,7 +118,7 @@ Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel | |||
| 118 | 118 | ||
| 119 | auto* port = Kernel::KPort::Create(kernel); | 119 | auto* port = Kernel::KPort::Create(kernel); |
| 120 | port->Initialize(max_sessions, false, service_name); | 120 | port->Initialize(max_sessions, false, service_name); |
| 121 | port->GetServerPort().SetHleHandler(shared_from_this()); | 121 | port->GetServerPort().SetSessionHandler(shared_from_this()); |
| 122 | 122 | ||
| 123 | port_installed = true; | 123 | port_installed = true; |
| 124 | 124 | ||
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index de530cbfb..147f12147 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -4,8 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/k_client_port.h" | ||
| 8 | #include "core/hle/kernel/k_client_session.h" | 10 | #include "core/hle/kernel/k_client_session.h" |
| 11 | #include "core/hle/kernel/k_port.h" | ||
| 12 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 13 | #include "core/hle/kernel/k_server_port.h" | ||
| 9 | #include "core/hle/kernel/k_server_session.h" | 14 | #include "core/hle/kernel/k_server_session.h" |
| 10 | #include "core/hle/kernel/k_session.h" | 15 | #include "core/hle/kernel/k_session.h" |
| 11 | #include "core/hle/service/sm/controller.h" | 16 | #include "core/hle/service/sm/controller.h" |
| @@ -13,7 +18,7 @@ | |||
| 13 | namespace Service::SM { | 18 | namespace Service::SM { |
| 14 | 19 | ||
| 15 | void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { | 20 | void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { |
| 16 | ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); | 21 | ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); |
| 17 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); | 22 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); |
| 18 | ctx.Session()->ConvertToDomain(); | 23 | ctx.Session()->ConvertToDomain(); |
| 19 | 24 | ||
| @@ -29,16 +34,36 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { | |||
| 29 | 34 | ||
| 30 | LOG_DEBUG(Service, "called"); | 35 | LOG_DEBUG(Service, "called"); |
| 31 | 36 | ||
| 32 | auto session = ctx.Session()->GetParent(); | 37 | auto& kernel = system.Kernel(); |
| 38 | auto* session = ctx.Session()->GetParent(); | ||
| 39 | auto* port = session->GetParent()->GetParent(); | ||
| 33 | 40 | ||
| 34 | // Open a reference to the session to simulate a new one being created. | 41 | // Reserve a new session from the process resource limit. |
| 35 | session->Open(); | 42 | Kernel::KScopedResourceReservation session_reservation( |
| 36 | session->GetClientSession().Open(); | 43 | kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); |
| 37 | session->GetServerSession().Open(); | 44 | if (!session_reservation.Succeeded()) { |
| 45 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 46 | rb.Push(Kernel::ResultLimitReached); | ||
| 47 | } | ||
| 38 | 48 | ||
| 49 | // Create a new session. | ||
| 50 | auto* clone = Kernel::KSession::Create(kernel); | ||
| 51 | clone->Initialize(&port->GetClientPort(), session->GetName()); | ||
| 52 | |||
| 53 | // Commit the session reservation. | ||
| 54 | session_reservation.Commit(); | ||
| 55 | |||
| 56 | // Enqueue the session with the named port. | ||
| 57 | port->EnqueueSession(&clone->GetServerSession()); | ||
| 58 | |||
| 59 | // Set the session request manager. | ||
| 60 | clone->GetServerSession().SetSessionRequestManager( | ||
| 61 | session->GetServerSession().GetSessionRequestManager()); | ||
| 62 | |||
| 63 | // We succeeded. | ||
| 39 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 40 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 41 | rb.PushMoveObjects(session->GetClientSession()); | 66 | rb.PushMoveObjects(clone->GetClientSession()); |
| 42 | } | 67 | } |
| 43 | 68 | ||
| 44 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { | 69 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 8cc9aee8a..a9bc7da74 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -150,31 +150,31 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& | |||
| 150 | IPC::RequestParser rp{ctx}; | 150 | IPC::RequestParser rp{ctx}; |
| 151 | std::string name(PopServiceName(rp)); | 151 | std::string name(PopServiceName(rp)); |
| 152 | 152 | ||
| 153 | // Find the named port. | ||
| 153 | auto result = service_manager.GetServicePort(name); | 154 | auto result = service_manager.GetServicePort(name); |
| 154 | if (result.Failed()) { | 155 | if (result.Failed()) { |
| 155 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); | 156 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); |
| 156 | return result.Code(); | 157 | return result.Code(); |
| 157 | } | 158 | } |
| 158 | |||
| 159 | auto* port = result.Unwrap(); | 159 | auto* port = result.Unwrap(); |
| 160 | 160 | ||
| 161 | // Kernel::KScopedResourceReservation session_reservation( | 161 | // Reserve a new session from the process resource limit. |
| 162 | // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); | 162 | Kernel::KScopedResourceReservation session_reservation( |
| 163 | // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); | 163 | kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); |
| 164 | R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); | ||
| 164 | 165 | ||
| 166 | // Create a new session. | ||
| 165 | auto* session = Kernel::KSession::Create(kernel); | 167 | auto* session = Kernel::KSession::Create(kernel); |
| 166 | session->Initialize(&port->GetClientPort(), std::move(name)); | 168 | session->Initialize(&port->GetClientPort(), std::move(name)); |
| 167 | 169 | ||
| 168 | // Commit the session reservation. | 170 | // Commit the session reservation. |
| 169 | // session_reservation.Commit(); | 171 | session_reservation.Commit(); |
| 170 | 172 | ||
| 171 | if (port->GetServerPort().GetHLEHandler()) { | 173 | // Enqueue the session with the named port. |
| 172 | port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); | 174 | port->EnqueueSession(&session->GetServerSession()); |
| 173 | } else { | ||
| 174 | port->EnqueueSession(&session->GetServerSession()); | ||
| 175 | } | ||
| 176 | 175 | ||
| 177 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); | 176 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); |
| 177 | |||
| 178 | return MakeResult(&session->GetClientSession()); | 178 | return MakeResult(&session->GetClientSession()); |
| 179 | } | 179 | } |
| 180 | 180 | ||
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 60f0b3f8a..ea37f11d4 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -73,7 +73,7 @@ public: | |||
| 73 | if (port == nullptr) { | 73 | if (port == nullptr) { |
| 74 | return nullptr; | 74 | return nullptr; |
| 75 | } | 75 | } |
| 76 | return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler()); | 76 | return std::static_pointer_cast<T>(port->GetServerPort().GetSessionRequestHandler()); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | void InvokeControlRequest(Kernel::HLERequestContext& context); | 79 | void InvokeControlRequest(Kernel::HLERequestContext& context); |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b4c56e1c1..bf2ef7816 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -82,22 +82,6 @@ struct Memory::Impl { | |||
| 82 | return nullptr; | 82 | return nullptr; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | u8* GetKernelBuffer(VAddr start_vaddr, size_t size) { | ||
| 86 | // TODO(bunnei): This is just a workaround until we have kernel memory layout mapped & | ||
| 87 | // managed. Until then, we use this to allocate and access kernel memory regions. | ||
| 88 | |||
| 89 | auto search = kernel_memory_regions.find(start_vaddr); | ||
| 90 | if (search != kernel_memory_regions.end()) { | ||
| 91 | return search->second.get(); | ||
| 92 | } | ||
| 93 | |||
| 94 | std::unique_ptr<u8[]> new_memory_region{new u8[size]}; | ||
| 95 | u8* raw_ptr = new_memory_region.get(); | ||
| 96 | kernel_memory_regions[start_vaddr] = std::move(new_memory_region); | ||
| 97 | |||
| 98 | return raw_ptr; | ||
| 99 | } | ||
| 100 | |||
| 101 | u8 Read8(const VAddr addr) { | 85 | u8 Read8(const VAddr addr) { |
| 102 | return Read<u8>(addr); | 86 | return Read<u8>(addr); |
| 103 | } | 87 | } |
| @@ -727,7 +711,6 @@ struct Memory::Impl { | |||
| 727 | } | 711 | } |
| 728 | 712 | ||
| 729 | Common::PageTable* current_page_table = nullptr; | 713 | Common::PageTable* current_page_table = nullptr; |
| 730 | std::unordered_map<VAddr, std::unique_ptr<u8[]>> kernel_memory_regions; | ||
| 731 | Core::System& system; | 714 | Core::System& system; |
| 732 | }; | 715 | }; |
| 733 | 716 | ||
| @@ -765,10 +748,6 @@ u8* Memory::GetPointer(VAddr vaddr) { | |||
| 765 | return impl->GetPointer(vaddr); | 748 | return impl->GetPointer(vaddr); |
| 766 | } | 749 | } |
| 767 | 750 | ||
| 768 | u8* Memory::GetKernelBuffer(VAddr start_vaddr, size_t size) { | ||
| 769 | return impl->GetKernelBuffer(start_vaddr, size); | ||
| 770 | } | ||
| 771 | |||
| 772 | const u8* Memory::GetPointer(VAddr vaddr) const { | 751 | const u8* Memory::GetPointer(VAddr vaddr) const { |
| 773 | return impl->GetPointer(vaddr); | 752 | return impl->GetPointer(vaddr); |
| 774 | } | 753 | } |
diff --git a/src/core/memory.h b/src/core/memory.h index 345fd870d..c91eeced9 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -121,15 +121,6 @@ public: | |||
| 121 | */ | 121 | */ |
| 122 | u8* GetPointer(VAddr vaddr); | 122 | u8* GetPointer(VAddr vaddr); |
| 123 | 123 | ||
| 124 | /** | ||
| 125 | * Gets a pointer to the start of a kernel heap allocated memory region. Will allocate one if it | ||
| 126 | * does not already exist. | ||
| 127 | * | ||
| 128 | * @param start_vaddr Start virtual address for the memory region. | ||
| 129 | * @param size Size of the memory region. | ||
| 130 | */ | ||
| 131 | u8* GetKernelBuffer(VAddr start_vaddr, size_t size); | ||
| 132 | |||
| 133 | template <typename T> | 124 | template <typename T> |
| 134 | T* GetPointer(VAddr vaddr) { | 125 | T* GetPointer(VAddr vaddr) { |
| 135 | return reinterpret_cast<T*>(GetPointer(vaddr)); | 126 | return reinterpret_cast<T*>(GetPointer(vaddr)); |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 822d0b555..b9b584b2a 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -323,7 +323,9 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { | |||
| 323 | return joystick->GetSDLJoystick() == sdl_joystick; | 323 | return joystick->GetSDLJoystick() == sdl_joystick; |
| 324 | }); | 324 | }); |
| 325 | 325 | ||
| 326 | (*joystick_it)->SetSDLJoystick(nullptr, nullptr); | 326 | if (joystick_it != joystick_guid_list.end()) { |
| 327 | (*joystick_it)->SetSDLJoystick(nullptr, nullptr); | ||
| 328 | } | ||
| 327 | } | 329 | } |
| 328 | 330 | ||
| 329 | void SDLState::HandleGameControllerEvent(const SDL_Event& event) { | 331 | void SDLState::HandleGameControllerEvent(const SDL_Event& event) { |
| @@ -1315,51 +1317,51 @@ public: | |||
| 1315 | void Start(const std::string& device_id) override { | 1317 | void Start(const std::string& device_id) override { |
| 1316 | SDLPoller::Start(device_id); | 1318 | SDLPoller::Start(device_id); |
| 1317 | // Reset stored axes | 1319 | // Reset stored axes |
| 1318 | analog_x_axis = -1; | 1320 | first_axis = -1; |
| 1319 | analog_y_axis = -1; | ||
| 1320 | } | 1321 | } |
| 1321 | 1322 | ||
| 1322 | Common::ParamPackage GetNextInput() override { | 1323 | Common::ParamPackage GetNextInput() override { |
| 1323 | SDL_Event event; | 1324 | SDL_Event event; |
| 1324 | while (state.event_queue.Pop(event)) { | 1325 | while (state.event_queue.Pop(event)) { |
| 1325 | // Filter out axis events that are below a threshold | 1326 | if (event.type != SDL_JOYAXISMOTION) { |
| 1326 | if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) { | 1327 | // Check for a button press |
| 1327 | continue; | ||
| 1328 | } | ||
| 1329 | if (event.type == SDL_JOYAXISMOTION) { | ||
| 1330 | const auto axis = event.jaxis.axis; | ||
| 1331 | // In order to return a complete analog param, we need inputs for both axes. | ||
| 1332 | // First we take the x-axis (horizontal) input, then the y-axis (vertical) input. | ||
| 1333 | if (analog_x_axis == -1) { | ||
| 1334 | analog_x_axis = axis; | ||
| 1335 | } else if (analog_y_axis == -1 && analog_x_axis != axis) { | ||
| 1336 | analog_y_axis = axis; | ||
| 1337 | } | ||
| 1338 | } else { | ||
| 1339 | // If the press wasn't accepted as a joy axis, check for a button press | ||
| 1340 | auto button_press = button_poller.FromEvent(event); | 1328 | auto button_press = button_poller.FromEvent(event); |
| 1341 | if (button_press) { | 1329 | if (button_press) { |
| 1342 | return *button_press; | 1330 | return *button_press; |
| 1343 | } | 1331 | } |
| 1332 | continue; | ||
| 1333 | } | ||
| 1334 | const auto axis = event.jaxis.axis; | ||
| 1335 | |||
| 1336 | // Filter out axis events that are below a threshold | ||
| 1337 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { | ||
| 1338 | continue; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | // Filter out axis events that are the same | ||
| 1342 | if (first_axis == axis) { | ||
| 1343 | continue; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | // In order to return a complete analog param, we need inputs for both axes. | ||
| 1347 | // If the first axis isn't set we set the value then wait till next event | ||
| 1348 | if (first_axis == -1) { | ||
| 1349 | first_axis = axis; | ||
| 1350 | continue; | ||
| 1344 | } | 1351 | } |
| 1345 | } | ||
| 1346 | 1352 | ||
| 1347 | if (analog_x_axis != -1 && analog_y_axis != -1) { | ||
| 1348 | if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { | 1353 | if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { |
| 1349 | auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | 1354 | auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), |
| 1350 | analog_x_axis, analog_y_axis); | 1355 | first_axis, axis); |
| 1351 | analog_x_axis = -1; | 1356 | first_axis = -1; |
| 1352 | analog_y_axis = -1; | ||
| 1353 | return params; | 1357 | return params; |
| 1354 | } | 1358 | } |
| 1355 | } | 1359 | } |
| 1356 | |||
| 1357 | return {}; | 1360 | return {}; |
| 1358 | } | 1361 | } |
| 1359 | 1362 | ||
| 1360 | private: | 1363 | private: |
| 1361 | int analog_x_axis = -1; | 1364 | int first_axis = -1; |
| 1362 | int analog_y_axis = -1; | ||
| 1363 | SDLButtonPoller button_poller; | 1365 | SDLButtonPoller button_poller; |
| 1364 | }; | 1366 | }; |
| 1365 | } // namespace Polling | 1367 | } // namespace Polling |