summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/k_server_session.cpp163
1 files changed, 124 insertions, 39 deletions
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index db3a07f91..f6ca3dc48 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -37,8 +37,6 @@ constexpr inline size_t ReceiveListDataSize =
37 37
38using ThreadQueueImplForKServerSessionRequest = KThreadQueue; 38using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
39 39
40static thread_local Common::ScratchBuffer<u8> temp_buffer;
41
42class ReceiveList { 40class ReceiveList {
43public: 41public:
44 static constexpr int GetEntryCount(const MessageBuffer::MessageHeader& header) { 42 static constexpr int GetEntryCount(const MessageBuffer::MessageHeader& header) {
@@ -269,12 +267,20 @@ Result ProcessReceiveMessagePointerDescriptors(int& offset, int& pointer_key,
269 R_UNLESS(recv_pointer != 0, ResultOutOfResource); 267 R_UNLESS(recv_pointer != 0, ResultOutOfResource);
270 268
271 // Perform the pointer data copy. 269 // Perform the pointer data copy.
272 // TODO: KProcessPageTable::CopyMemoryFromHeapToHeapWithoutCheckDestination 270 if (dst_user) {
273 // TODO: KProcessPageTable::CopyMemoryFromLinearToUser 271 R_TRY(src_page_table.CopyMemoryFromHeapToHeapWithoutCheckDestination(
274 272 dst_page_table, recv_pointer, recv_size, KMemoryState::FlagReferenceCounted,
275 temp_buffer.resize_destructive(recv_size); 273 KMemoryState::FlagReferenceCounted,
276 src_page_table.GetMemory().ReadBlock(src_pointer, temp_buffer.data(), recv_size); 274 KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite,
277 dst_page_table.GetMemory().WriteBlock(recv_pointer, temp_buffer.data(), recv_size); 275 KMemoryAttribute::Uncached | KMemoryAttribute::Locked, KMemoryAttribute::Locked,
276 src_pointer, KMemoryState::FlagLinearMapped, KMemoryState::FlagLinearMapped,
277 KMemoryPermission::UserRead, KMemoryAttribute::Uncached, KMemoryAttribute::None));
278 } else {
279 R_TRY(src_page_table.CopyMemoryFromLinearToUser(
280 recv_pointer, recv_size, src_pointer, KMemoryState::FlagLinearMapped,
281 KMemoryState::FlagLinearMapped, KMemoryPermission::UserRead,
282 KMemoryAttribute::Uncached, KMemoryAttribute::None));
283 }
278 } 284 }
279 285
280 // Set the output descriptor. 286 // Set the output descriptor.
@@ -303,21 +309,22 @@ constexpr Result GetMapAliasMemoryState(KMemoryState& out,
303 R_SUCCEED(); 309 R_SUCCEED();
304} 310}
305 311
306constexpr Result GetMapAliasTestStateAndAttributeMask(u32& out_state, u32& out_attr_mask, 312constexpr Result GetMapAliasTestStateAndAttributeMask(KMemoryState& out_state,
313 KMemoryAttribute& out_attr_mask,
307 KMemoryState state) { 314 KMemoryState state) {
308 switch (state) { 315 switch (state) {
309 case KMemoryState::Ipc: 316 case KMemoryState::Ipc:
310 out_state = static_cast<u32>(KMemoryState::FlagCanUseIpc); 317 out_state = KMemoryState::FlagCanUseIpc;
311 out_attr_mask = static_cast<u32>(KMemoryAttribute::Uncached | 318 out_attr_mask =
312 KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked); 319 KMemoryAttribute::Uncached | KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked;
313 break; 320 break;
314 case KMemoryState::NonSecureIpc: 321 case KMemoryState::NonSecureIpc:
315 out_state = static_cast<u32>(KMemoryState::FlagCanUseNonSecureIpc); 322 out_state = KMemoryState::FlagCanUseNonSecureIpc;
316 out_attr_mask = static_cast<u32>(KMemoryAttribute::Uncached | KMemoryAttribute::Locked); 323 out_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked;
317 break; 324 break;
318 case KMemoryState::NonDeviceIpc: 325 case KMemoryState::NonDeviceIpc:
319 out_state = static_cast<u32>(KMemoryState::FlagCanUseNonDeviceIpc); 326 out_state = KMemoryState::FlagCanUseNonDeviceIpc;
320 out_attr_mask = static_cast<u32>(KMemoryAttribute::Uncached | KMemoryAttribute::Locked); 327 out_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked;
321 break; 328 break;
322 default: 329 default:
323 R_THROW(ResultInvalidCombination); 330 R_THROW(ResultInvalidCombination);
@@ -708,13 +715,48 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
708 if (!dst_user && !src_user) { 715 if (!dst_user && !src_user) {
709 // Fast case is TLS -> TLS, do raw memcpy if we can. 716 // Fast case is TLS -> TLS, do raw memcpy if we can.
710 std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size); 717 std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size);
711 } else { 718 } else if (dst_user) {
719 // Determine how much fast size we can copy.
720 const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize);
721 const size_t fast_size = max_fast_size - offset_words;
722
723 // Determine source state; if user buffer, we require heap, and otherwise only linear
724 // mapped (to enable tls use).
725 const auto src_state =
726 src_user ? KMemoryState::FlagReferenceCounted : KMemoryState::FlagLinearMapped;
727
728 // Determine the source permission. User buffer should be unmapped + read, TLS should be
729 // user readable.
730 const KMemoryPermission src_perm = static_cast<KMemoryPermission>(
731 src_user ? KMemoryPermission::NotMapped | KMemoryPermission::KernelRead
732 : KMemoryPermission::UserRead);
733
734 // Perform the fast part of the copy.
735 R_TRY(src_page_table.CopyMemoryFromLinearToKernel(
736 dst_msg_ptr + offset, fast_size, src_message_buffer + offset_words, src_state,
737 src_state, src_perm, KMemoryAttribute::Uncached, KMemoryAttribute::None));
738
739 // If the fast part of the copy didn't get everything, perform the slow part of the
740 // copy.
741 if (fast_size < raw_size) {
742 R_TRY(src_page_table.CopyMemoryFromHeapToHeap(
743 dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size,
744 KMemoryState::FlagReferenceCounted, KMemoryState::FlagReferenceCounted,
745 KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite,
746 KMemoryAttribute::Uncached | KMemoryAttribute::Locked, KMemoryAttribute::Locked,
747 src_message_buffer + max_fast_size, src_state, src_state, src_perm,
748 KMemoryAttribute::Uncached, KMemoryAttribute::None));
749 }
750 } else /* if (src_user) */ {
751 // The source is a user buffer, so it should be unmapped + readable.
752 constexpr KMemoryPermission SourcePermission = static_cast<KMemoryPermission>(
753 KMemoryPermission::NotMapped | KMemoryPermission::KernelRead);
754
712 // Copy the memory. 755 // Copy the memory.
713 temp_buffer.resize_destructive(raw_size); 756 R_TRY(src_page_table.CopyMemoryFromLinearToUser(
714 src_page_table.GetMemory().ReadBlock(src_message_buffer + offset_words, 757 dst_message_buffer + offset_words, raw_size, src_message_buffer + offset_words,
715 temp_buffer.data(), raw_size); 758 KMemoryState::FlagReferenceCounted, KMemoryState::FlagReferenceCounted,
716 dst_page_table.GetMemory().WriteBlock(dst_message_buffer + offset_words, 759 SourcePermission, KMemoryAttribute::Uncached, KMemoryAttribute::None));
717 temp_buffer.data(), raw_size);
718 } 760 }
719 } 761 }
720 762
@@ -731,8 +773,8 @@ Result ProcessSendMessageReceiveMapping(KProcessPageTable& src_page_table,
731 R_SUCCEED_IF(size == 0); 773 R_SUCCEED_IF(size == 0);
732 774
733 // Get the memory state and attribute mask to test. 775 // Get the memory state and attribute mask to test.
734 u32 test_state; 776 KMemoryState test_state;
735 u32 test_attr_mask; 777 KMemoryAttribute test_attr_mask;
736 R_TRY(GetMapAliasTestStateAndAttributeMask(test_state, test_attr_mask, src_state)); 778 R_TRY(GetMapAliasTestStateAndAttributeMask(test_state, test_attr_mask, src_state));
737 779
738 // Determine buffer extents. 780 // Determine buffer extents.
@@ -749,18 +791,18 @@ Result ProcessSendMessageReceiveMapping(KProcessPageTable& src_page_table,
749 if (aligned_dst_start != mapping_dst_start) { 791 if (aligned_dst_start != mapping_dst_start) {
750 ASSERT(client_address < mapping_dst_start); 792 ASSERT(client_address < mapping_dst_start);
751 const size_t copy_size = std::min<size_t>(size, mapping_dst_start - client_address); 793 const size_t copy_size = std::min<size_t>(size, mapping_dst_start - client_address);
752 temp_buffer.resize_destructive(copy_size); 794 R_TRY(dst_page_table.CopyMemoryFromUserToLinear(
753 src_page_table.GetMemory().ReadBlock(client_address, temp_buffer.data(), copy_size); 795 client_address, copy_size, test_state, test_state, KMemoryPermission::UserReadWrite,
754 dst_page_table.GetMemory().WriteBlock(server_address, temp_buffer.data(), copy_size); 796 test_attr_mask, KMemoryAttribute::None, server_address));
755 } 797 }
756 798
757 // If the end of the buffer is unaligned, handle that. 799 // If the end of the buffer is unaligned, handle that.
758 if (mapping_dst_end < aligned_dst_end && 800 if (mapping_dst_end < aligned_dst_end &&
759 (aligned_dst_start == mapping_dst_start || aligned_dst_start < mapping_dst_end)) { 801 (aligned_dst_start == mapping_dst_start || aligned_dst_start < mapping_dst_end)) {
760 const size_t copy_size = client_address + size - mapping_dst_end; 802 const size_t copy_size = client_address + size - mapping_dst_end;
761 temp_buffer.resize_destructive(copy_size); 803 R_TRY(dst_page_table.CopyMemoryFromUserToLinear(
762 src_page_table.GetMemory().ReadBlock(mapping_src_end, temp_buffer.data(), copy_size); 804 mapping_dst_end, copy_size, test_state, test_state, KMemoryPermission::UserReadWrite,
763 dst_page_table.GetMemory().WriteBlock(mapping_dst_end, temp_buffer.data(), copy_size); 805 test_attr_mask, KMemoryAttribute::None, mapping_src_end));
764 } 806 }
765 807
766 R_SUCCEED(); 808 R_SUCCEED();
@@ -796,9 +838,15 @@ Result ProcessSendMessagePointerDescriptors(int& offset, int& pointer_key,
796 R_UNLESS(recv_pointer != 0, ResultOutOfResource); 838 R_UNLESS(recv_pointer != 0, ResultOutOfResource);
797 839
798 // Perform the pointer data copy. 840 // Perform the pointer data copy.
799 temp_buffer.resize_destructive(recv_size); 841 const bool dst_heap = dst_user && dst_recv_list.IsToMessageBuffer();
800 src_page_table.GetMemory().ReadBlock(src_pointer, temp_buffer.data(), recv_size); 842 const auto dst_state =
801 dst_page_table.GetMemory().WriteBlock(recv_pointer, temp_buffer.data(), recv_size); 843 dst_heap ? KMemoryState::FlagReferenceCounted : KMemoryState::FlagLinearMapped;
844 const KMemoryPermission dst_perm =
845 dst_heap ? KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite
846 : KMemoryPermission::UserReadWrite;
847 R_TRY(dst_page_table.CopyMemoryFromUserToLinear(
848 recv_pointer, recv_size, dst_state, dst_state, dst_perm, KMemoryAttribute::Uncached,
849 KMemoryAttribute::None, src_pointer));
802 } 850 }
803 851
804 // Set the output descriptor. 852 // Set the output descriptor.
@@ -964,13 +1012,50 @@ Result SendMessage(KernelCore& kernel, uint64_t src_message_buffer, size_t src_b
964 if (!dst_user && !src_user) { 1012 if (!dst_user && !src_user) {
965 // Fast case is TLS -> TLS, do raw memcpy if we can. 1013 // Fast case is TLS -> TLS, do raw memcpy if we can.
966 std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size); 1014 std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size);
967 } else { 1015 } else if (src_user) {
1016 // Determine how much fast size we can copy.
1017 const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize);
1018 const size_t fast_size = max_fast_size - offset_words;
1019
1020 // Determine dst state; if user buffer, we require heap, and otherwise only linear
1021 // mapped (to enable tls use).
1022 const auto dst_state =
1023 dst_user ? KMemoryState::FlagReferenceCounted : KMemoryState::FlagLinearMapped;
1024
1025 // Determine the dst permission. User buffer should be unmapped + read, TLS should
1026 // be user readable.
1027 const KMemoryPermission dst_perm =
1028 dst_user ? KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite
1029 : KMemoryPermission::UserReadWrite;
1030
1031 // Perform the fast part of the copy.
1032 R_TRY(dst_page_table.CopyMemoryFromKernelToLinear(
1033 dst_message_buffer + offset_words, fast_size, dst_state, dst_state, dst_perm,
1034 KMemoryAttribute::Uncached, KMemoryAttribute::None, src_msg_ptr + offset));
1035
1036 // If the fast part of the copy didn't get everything, perform the slow part of the
1037 // copy.
1038 if (fast_size < raw_size) {
1039 R_TRY(dst_page_table.CopyMemoryFromHeapToHeap(
1040 dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size,
1041 dst_state, dst_state, dst_perm, KMemoryAttribute::Uncached,
1042 KMemoryAttribute::None, src_message_buffer + max_fast_size,
1043 KMemoryState::FlagReferenceCounted, KMemoryState::FlagReferenceCounted,
1044 KMemoryPermission::NotMapped | KMemoryPermission::KernelRead,
1045 KMemoryAttribute::Uncached | KMemoryAttribute::Locked,
1046 KMemoryAttribute::Locked));
1047 }
1048 } else /* if (dst_user) */ {
1049 // The destination is a user buffer, so it should be unmapped + readable.
1050 constexpr KMemoryPermission DestinationPermission =
1051 KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite;
1052
968 // Copy the memory. 1053 // Copy the memory.
969 temp_buffer.resize_destructive(raw_size); 1054 R_TRY(dst_page_table.CopyMemoryFromUserToLinear(
970 src_page_table.GetMemory().ReadBlock(src_message_buffer + offset_words, 1055 dst_message_buffer + offset_words, raw_size, KMemoryState::FlagReferenceCounted,
971 temp_buffer.data(), raw_size); 1056 KMemoryState::FlagReferenceCounted, DestinationPermission,
972 dst_page_table.GetMemory().WriteBlock(dst_message_buffer + offset_words, 1057 KMemoryAttribute::Uncached, KMemoryAttribute::None,
973 temp_buffer.data(), raw_size); 1058 src_message_buffer + offset_words));
974 } 1059 }
975 } 1060 }
976 } 1061 }