diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/kernel/k_memory_block.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.cpp | 39 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.h | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 25 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_shared_memory.cpp | 31 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_shared_memory.h | 19 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 24 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 138 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc_wrap.h | 17 |
10 files changed, 210 insertions, 95 deletions
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index c5b9c5e85..a7fdb5fb8 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h | |||
| @@ -134,6 +134,10 @@ enum class KMemoryPermission : u8 { | |||
| 134 | }; | 134 | }; |
| 135 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); | 135 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); |
| 136 | 136 | ||
| 137 | constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) { | ||
| 138 | return static_cast<KMemoryPermission>(perm); | ||
| 139 | } | ||
| 140 | |||
| 137 | enum class KMemoryAttribute : u8 { | 141 | enum class KMemoryAttribute : u8 { |
| 138 | None = 0x00, | 142 | None = 0x00, |
| 139 | Mask = 0x7F, | 143 | Mask = 0x7F, |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 2f33cb6c1..6c5d7d602 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -641,6 +641,45 @@ ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, K | |||
| 641 | return RESULT_SUCCESS; | 641 | return RESULT_SUCCESS; |
| 642 | } | 642 | } |
| 643 | 643 | ||
| 644 | ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) { | ||
| 645 | VAddr cur_addr{addr}; | ||
| 646 | |||
| 647 | for (const auto& node : page_linked_list.Nodes()) { | ||
| 648 | const std::size_t num_pages{(addr - cur_addr) / PageSize}; | ||
| 649 | if (const auto result{ | ||
| 650 | Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)}; | ||
| 651 | result.IsError()) { | ||
| 652 | return result; | ||
| 653 | } | ||
| 654 | |||
| 655 | cur_addr += node.GetNumPages() * PageSize; | ||
| 656 | } | ||
| 657 | |||
| 658 | return RESULT_SUCCESS; | ||
| 659 | } | ||
| 660 | |||
| 661 | ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, | ||
| 662 | KMemoryState state) { | ||
| 663 | std::lock_guard lock{page_table_lock}; | ||
| 664 | |||
| 665 | const std::size_t num_pages{page_linked_list.GetNumPages()}; | ||
| 666 | const std::size_t size{num_pages * PageSize}; | ||
| 667 | |||
| 668 | if (!CanContain(addr, size, state)) { | ||
| 669 | return ResultInvalidCurrentMemory; | ||
| 670 | } | ||
| 671 | |||
| 672 | if (IsRegionMapped(addr, num_pages * PageSize)) { | ||
| 673 | return ResultInvalidCurrentMemory; | ||
| 674 | } | ||
| 675 | |||
| 676 | CASCADE_CODE(UnmapPages(addr, page_linked_list)); | ||
| 677 | |||
| 678 | block_manager->Update(addr, num_pages, state, KMemoryPermission::None); | ||
| 679 | |||
| 680 | return RESULT_SUCCESS; | ||
| 681 | } | ||
| 682 | |||
| 644 | ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, | 683 | ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, |
| 645 | KMemoryPermission perm) { | 684 | KMemoryPermission perm) { |
| 646 | 685 | ||
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 80a1586db..baec7c260 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -40,6 +40,7 @@ public: | |||
| 40 | ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); | 40 | ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); |
| 41 | ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, | 41 | ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, |
| 42 | KMemoryPermission perm); | 42 | KMemoryPermission perm); |
| 43 | ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); | ||
| 43 | ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); | 44 | ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); |
| 44 | KMemoryInfo QueryInfo(VAddr addr); | 45 | KMemoryInfo QueryInfo(VAddr addr); |
| 45 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); | 46 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); |
| @@ -63,6 +64,8 @@ public: | |||
| 63 | return page_table_impl; | 64 | return page_table_impl; |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 67 | constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; | ||
| 68 | |||
| 66 | private: | 69 | private: |
| 67 | enum class OperationType : u32 { | 70 | enum class OperationType : u32 { |
| 68 | Map, | 71 | Map, |
| @@ -79,6 +82,7 @@ private: | |||
| 79 | ResultCode InitializeMemoryLayout(VAddr start, VAddr end); | 82 | ResultCode InitializeMemoryLayout(VAddr start, VAddr end); |
| 80 | ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, | 83 | ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, |
| 81 | KMemoryPermission perm); | 84 | KMemoryPermission perm); |
| 85 | ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list); | ||
| 82 | void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); | 86 | void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); |
| 83 | bool IsRegionMapped(VAddr address, u64 size); | 87 | bool IsRegionMapped(VAddr address, u64 size); |
| 84 | bool IsRegionContiguous(VAddr addr, u64 size) const; | 88 | bool IsRegionContiguous(VAddr addr, u64 size) const; |
| @@ -92,7 +96,6 @@ private: | |||
| 92 | OperationType operation, PAddr map_addr = 0); | 96 | OperationType operation, PAddr map_addr = 0); |
| 93 | constexpr VAddr GetRegionAddress(KMemoryState state) const; | 97 | constexpr VAddr GetRegionAddress(KMemoryState state) const; |
| 94 | constexpr std::size_t GetRegionSize(KMemoryState state) const; | 98 | constexpr std::size_t GetRegionSize(KMemoryState state) const; |
| 95 | constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; | ||
| 96 | 99 | ||
| 97 | constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, | 100 | constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, |
| 98 | KMemoryState state, KMemoryPermission perm_mask, | 101 | KMemoryState state, KMemoryPermission perm_mask, |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index edc3b5175..e542b1f07 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "core/hle/kernel/k_resource_limit.h" | 21 | #include "core/hle/kernel/k_resource_limit.h" |
| 22 | #include "core/hle/kernel/k_scheduler.h" | 22 | #include "core/hle/kernel/k_scheduler.h" |
| 23 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | 23 | #include "core/hle/kernel/k_scoped_resource_reservation.h" |
| 24 | #include "core/hle/kernel/k_shared_memory.h" | ||
| 24 | #include "core/hle/kernel/k_slab_heap.h" | 25 | #include "core/hle/kernel/k_slab_heap.h" |
| 25 | #include "core/hle/kernel/k_thread.h" | 26 | #include "core/hle/kernel/k_thread.h" |
| 26 | #include "core/hle/kernel/kernel.h" | 27 | #include "core/hle/kernel/kernel.h" |
| @@ -247,6 +248,30 @@ void KProcess::UnpinCurrentThread() { | |||
| 247 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 248 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 248 | } | 249 | } |
| 249 | 250 | ||
| 251 | ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, | ||
| 252 | [[maybe_unused]] size_t size) { | ||
| 253 | // Lock ourselves, to prevent concurrent access. | ||
| 254 | KScopedLightLock lk(state_lock); | ||
| 255 | |||
| 256 | // TODO(bunnei): Manage KSharedMemoryInfo list here. | ||
| 257 | |||
| 258 | // Open a reference to the shared memory. | ||
| 259 | shmem->Open(); | ||
| 260 | |||
| 261 | return RESULT_SUCCESS; | ||
| 262 | } | ||
| 263 | |||
| 264 | void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, | ||
| 265 | [[maybe_unused]] size_t size) { | ||
| 266 | // Lock ourselves, to prevent concurrent access. | ||
| 267 | KScopedLightLock lk(state_lock); | ||
| 268 | |||
| 269 | // TODO(bunnei): Manage KSharedMemoryInfo list here. | ||
| 270 | |||
| 271 | // Close a reference to the shared memory. | ||
| 272 | shmem->Close(); | ||
| 273 | } | ||
| 274 | |||
| 250 | void KProcess::RegisterThread(const KThread* thread) { | 275 | void KProcess::RegisterThread(const KThread* thread) { |
| 251 | thread_list.push_back(thread); | 276 | thread_list.push_back(thread); |
| 252 | } | 277 | } |
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 961c0d9ba..5c54c6360 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h | |||
| @@ -352,6 +352,9 @@ public: | |||
| 352 | return state_lock; | 352 | return state_lock; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | ResultCode AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size); | ||
| 356 | void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size); | ||
| 357 | |||
| 355 | /////////////////////////////////////////////////////////////////////////////////////////////// | 358 | /////////////////////////////////////////////////////////////////////////////////////////////// |
| 356 | // Thread-local storage management | 359 | // Thread-local storage management |
| 357 | 360 | ||
diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index f137a182a..1da57a4c3 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp | |||
| @@ -20,9 +20,10 @@ KSharedMemory::~KSharedMemory() { | |||
| 20 | 20 | ||
| 21 | ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, | 21 | ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, |
| 22 | KProcess* owner_process_, KPageLinkedList&& page_list_, | 22 | KProcess* owner_process_, KPageLinkedList&& page_list_, |
| 23 | KMemoryPermission owner_permission_, | 23 | Svc::MemoryPermission owner_permission_, |
| 24 | KMemoryPermission user_permission_, PAddr physical_address_, | 24 | Svc::MemoryPermission user_permission_, |
| 25 | std::size_t size_, std::string name_) { | 25 | PAddr physical_address_, std::size_t size_, |
| 26 | std::string name_) { | ||
| 26 | // Set members. | 27 | // Set members. |
| 27 | owner_process = owner_process_; | 28 | owner_process = owner_process_; |
| 28 | device_memory = &device_memory_; | 29 | device_memory = &device_memory_; |
| @@ -58,14 +59,6 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de | |||
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | void KSharedMemory::Finalize() { | 61 | void KSharedMemory::Finalize() { |
| 61 | ///* Get the number of pages. */ | ||
| 62 | // const size_t num_pages = m_page_group.GetNumPages(); | ||
| 63 | // const size_t size = num_pages * PageSize; | ||
| 64 | |||
| 65 | ///* Close and finalize the page group. */ | ||
| 66 | // m_page_group.Close(); | ||
| 67 | // m_page_group.Finalize(); | ||
| 68 | |||
| 69 | // Release the memory reservation. | 62 | // Release the memory reservation. |
| 70 | resource_limit->Release(LimitableResource::PhysicalMemory, size); | 63 | resource_limit->Release(LimitableResource::PhysicalMemory, size); |
| 71 | resource_limit->Close(); | 64 | resource_limit->Close(); |
| @@ -75,14 +68,14 @@ void KSharedMemory::Finalize() { | |||
| 75 | } | 68 | } |
| 76 | 69 | ||
| 77 | ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t size, | 70 | ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t size, |
| 78 | KMemoryPermission permissions) { | 71 | Svc::MemoryPermission permissions) { |
| 79 | const u64 page_count{(size + PageSize - 1) / PageSize}; | 72 | const u64 page_count{(size + PageSize - 1) / PageSize}; |
| 80 | 73 | ||
| 81 | if (page_list.GetNumPages() != page_count) { | 74 | if (page_list.GetNumPages() != page_count) { |
| 82 | UNIMPLEMENTED_MSG("Page count does not match"); | 75 | UNIMPLEMENTED_MSG("Page count does not match"); |
| 83 | } | 76 | } |
| 84 | 77 | ||
| 85 | const KMemoryPermission expected = | 78 | const Svc::MemoryPermission expected = |
| 86 | &target_process == owner_process ? owner_permission : user_permission; | 79 | &target_process == owner_process ? owner_permission : user_permission; |
| 87 | 80 | ||
| 88 | if (permissions != expected) { | 81 | if (permissions != expected) { |
| @@ -90,7 +83,17 @@ ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size | |||
| 90 | } | 83 | } |
| 91 | 84 | ||
| 92 | return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared, | 85 | return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared, |
| 93 | permissions); | 86 | ConvertToKMemoryPermission(permissions)); |
| 87 | } | ||
| 88 | |||
| 89 | ResultCode KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t size) { | ||
| 90 | const u64 page_count{(size + PageSize - 1) / PageSize}; | ||
| 91 | |||
| 92 | if (page_list.GetNumPages() != page_count) { | ||
| 93 | UNIMPLEMENTED_MSG("Page count does not match"); | ||
| 94 | } | ||
| 95 | |||
| 96 | return target_process.PageTable().UnmapPages(address, page_list, KMemoryState::Shared); | ||
| 94 | } | 97 | } |
| 95 | 98 | ||
| 96 | } // namespace Kernel | 99 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 2d315c916..28939c93c 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h | |||
| @@ -29,8 +29,9 @@ public: | |||
| 29 | 29 | ||
| 30 | ResultCode Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, | 30 | ResultCode Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, |
| 31 | KProcess* owner_process_, KPageLinkedList&& page_list_, | 31 | KProcess* owner_process_, KPageLinkedList&& page_list_, |
| 32 | KMemoryPermission owner_permission_, KMemoryPermission user_permission_, | 32 | Svc::MemoryPermission owner_permission_, |
| 33 | PAddr physical_address_, std::size_t size_, std::string name_); | 33 | Svc::MemoryPermission user_permission_, PAddr physical_address_, |
| 34 | std::size_t size_, std::string name_); | ||
| 34 | 35 | ||
| 35 | /** | 36 | /** |
| 36 | * Maps a shared memory block to an address in the target process' address space | 37 | * Maps a shared memory block to an address in the target process' address space |
| @@ -40,7 +41,15 @@ public: | |||
| 40 | * @param permissions Memory block map permissions (specified by SVC field) | 41 | * @param permissions Memory block map permissions (specified by SVC field) |
| 41 | */ | 42 | */ |
| 42 | ResultCode Map(KProcess& target_process, VAddr address, std::size_t size, | 43 | ResultCode Map(KProcess& target_process, VAddr address, std::size_t size, |
| 43 | KMemoryPermission permissions); | 44 | Svc::MemoryPermission permissions); |
| 45 | |||
| 46 | /** | ||
| 47 | * Unmaps a shared memory block from an address in the target process' address space | ||
| 48 | * @param target_process Process on which to unmap the memory block | ||
| 49 | * @param address Address in system memory to unmap shared memory block | ||
| 50 | * @param size Size of the shared memory block to unmap | ||
| 51 | */ | ||
| 52 | ResultCode Unmap(KProcess& target_process, VAddr address, std::size_t size); | ||
| 44 | 53 | ||
| 45 | /** | 54 | /** |
| 46 | * Gets a pointer to the shared memory block | 55 | * Gets a pointer to the shared memory block |
| @@ -71,8 +80,8 @@ private: | |||
| 71 | Core::DeviceMemory* device_memory; | 80 | Core::DeviceMemory* device_memory; |
| 72 | KProcess* owner_process{}; | 81 | KProcess* owner_process{}; |
| 73 | KPageLinkedList page_list; | 82 | KPageLinkedList page_list; |
| 74 | KMemoryPermission owner_permission{}; | 83 | Svc::MemoryPermission owner_permission{}; |
| 75 | KMemoryPermission user_permission{}; | 84 | Svc::MemoryPermission user_permission{}; |
| 76 | PAddr physical_address{}; | 85 | PAddr physical_address{}; |
| 77 | std::size_t size{}; | 86 | std::size_t size{}; |
| 78 | KResourceLimit* resource_limit{}; | 87 | KResourceLimit* resource_limit{}; |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 718525c4c..f64e07081 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -599,21 +599,21 @@ struct KernelCore::Impl { | |||
| 599 | time_shared_mem = KSharedMemory::Create(system.Kernel()); | 599 | time_shared_mem = KSharedMemory::Create(system.Kernel()); |
| 600 | 600 | ||
| 601 | hid_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, | 601 | hid_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, |
| 602 | {hid_phys_addr, hid_size / PageSize}, KMemoryPermission::None, | 602 | {hid_phys_addr, hid_size / PageSize}, |
| 603 | KMemoryPermission::Read, hid_phys_addr, hid_size, | 603 | Svc::MemoryPermission::None, Svc::MemoryPermission::Read, |
| 604 | "HID:SharedMemory"); | 604 | hid_phys_addr, hid_size, "HID:SharedMemory"); |
| 605 | font_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, | 605 | font_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, |
| 606 | {font_phys_addr, font_size / PageSize}, KMemoryPermission::None, | 606 | {font_phys_addr, font_size / PageSize}, |
| 607 | KMemoryPermission::Read, font_phys_addr, font_size, | 607 | Svc::MemoryPermission::None, Svc::MemoryPermission::Read, |
| 608 | "Font:SharedMemory"); | 608 | font_phys_addr, font_size, "Font:SharedMemory"); |
| 609 | irs_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, | 609 | irs_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, |
| 610 | {irs_phys_addr, irs_size / PageSize}, KMemoryPermission::None, | 610 | {irs_phys_addr, irs_size / PageSize}, |
| 611 | KMemoryPermission::Read, irs_phys_addr, irs_size, | 611 | Svc::MemoryPermission::None, Svc::MemoryPermission::Read, |
| 612 | "IRS:SharedMemory"); | 612 | irs_phys_addr, irs_size, "IRS:SharedMemory"); |
| 613 | time_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, | 613 | time_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, |
| 614 | {time_phys_addr, time_size / PageSize}, KMemoryPermission::None, | 614 | {time_phys_addr, time_size / PageSize}, |
| 615 | KMemoryPermission::Read, time_phys_addr, time_size, | 615 | Svc::MemoryPermission::None, Svc::MemoryPermission::Read, |
| 616 | "Time:SharedMemory"); | 616 | time_phys_addr, time_size, "Time:SharedMemory"); |
| 617 | } | 617 | } |
| 618 | 618 | ||
| 619 | void InitializePageSlab() { | 619 | void InitializePageSlab() { |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 725f16ea4..156c565b0 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -1183,79 +1183,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) { | |||
| 1183 | return GetCurrentProcessorNumber(system); | 1183 | return GetCurrentProcessorNumber(system); |
| 1184 | } | 1184 | } |
| 1185 | 1185 | ||
| 1186 | static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, | 1186 | constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { |
| 1187 | u64 size, u32 permissions) { | 1187 | switch (perm) { |
| 1188 | std::lock_guard lock{HLE::g_hle_lock}; | 1188 | case Svc::MemoryPermission::Read: |
| 1189 | case Svc::MemoryPermission::ReadWrite: | ||
| 1190 | return true; | ||
| 1191 | default: | ||
| 1192 | return false; | ||
| 1193 | } | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1197 | return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, | ||
| 1201 | u64 size, Svc::MemoryPermission map_perm) { | ||
| 1189 | LOG_TRACE(Kernel_SVC, | 1202 | LOG_TRACE(Kernel_SVC, |
| 1190 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", | 1203 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", |
| 1191 | shared_memory_handle, addr, size, permissions); | 1204 | shmem_handle, address, size, map_perm); |
| 1192 | 1205 | ||
| 1193 | if (!Common::Is4KBAligned(addr)) { | 1206 | // Validate the address/size. |
| 1194 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | 1207 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); |
| 1195 | return ResultInvalidAddress; | 1208 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); |
| 1196 | } | 1209 | R_UNLESS(size > 0, ResultInvalidSize); |
| 1210 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 1197 | 1211 | ||
| 1198 | if (size == 0) { | 1212 | // Validate the permission. |
| 1199 | LOG_ERROR(Kernel_SVC, "Size is 0"); | 1213 | R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); |
| 1200 | return ResultInvalidSize; | ||
| 1201 | } | ||
| 1202 | 1214 | ||
| 1203 | if (!Common::Is4KBAligned(size)) { | 1215 | // Get the current process. |
| 1204 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | 1216 | auto& process = *system.Kernel().CurrentProcess(); |
| 1205 | return ResultInvalidSize; | 1217 | auto& page_table = process.PageTable(); |
| 1206 | } | ||
| 1207 | 1218 | ||
| 1208 | if (!IsValidAddressRange(addr, size)) { | 1219 | // Get the shared memory. |
| 1209 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | 1220 | KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); |
| 1210 | addr, size); | 1221 | R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); |
| 1211 | return ResultInvalidCurrentMemory; | ||
| 1212 | } | ||
| 1213 | 1222 | ||
| 1214 | const auto permission_type = static_cast<MemoryPermission>(permissions); | 1223 | // Verify that the mapping is in range. |
| 1215 | if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { | 1224 | R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); |
| 1216 | LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", | ||
| 1217 | permissions); | ||
| 1218 | return ResultInvalidNewMemoryPermission; | ||
| 1219 | } | ||
| 1220 | 1225 | ||
| 1221 | auto* const current_process{system.Kernel().CurrentProcess()}; | 1226 | // Add the shared memory to the process. |
| 1222 | auto& page_table{current_process->PageTable()}; | 1227 | R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size)); |
| 1223 | 1228 | ||
| 1224 | if (page_table.IsInvalidRegion(addr, size)) { | 1229 | // Ensure that we clean up the shared memory if we fail to map it. |
| 1225 | LOG_ERROR(Kernel_SVC, | 1230 | auto guard = |
| 1226 | "Addr does not fit within the valid region, addr=0x{:016X}, " | 1231 | SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); }); |
| 1227 | "size=0x{:016X}", | ||
| 1228 | addr, size); | ||
| 1229 | return ResultInvalidMemoryRegion; | ||
| 1230 | } | ||
| 1231 | 1232 | ||
| 1232 | if (page_table.IsInsideHeapRegion(addr, size)) { | 1233 | // Map the shared memory. |
| 1233 | LOG_ERROR(Kernel_SVC, | 1234 | R_TRY(shmem->Map(process, address, size, map_perm)); |
| 1234 | "Addr does not fit within the heap region, addr=0x{:016X}, " | ||
| 1235 | "size=0x{:016X}", | ||
| 1236 | addr, size); | ||
| 1237 | return ResultInvalidMemoryRegion; | ||
| 1238 | } | ||
| 1239 | 1235 | ||
| 1240 | if (page_table.IsInsideAliasRegion(addr, size)) { | 1236 | // We succeeded. |
| 1241 | LOG_ERROR(Kernel_SVC, | 1237 | guard.Cancel(); |
| 1242 | "Address does not fit within the map region, addr=0x{:016X}, " | 1238 | return RESULT_SUCCESS; |
| 1243 | "size=0x{:016X}", | 1239 | } |
| 1244 | addr, size); | 1240 | |
| 1245 | return ResultInvalidMemoryRegion; | 1241 | static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, |
| 1246 | } | 1242 | u32 size, Svc::MemoryPermission map_perm) { |
| 1243 | return MapSharedMemory(system, shmem_handle, address, size, map_perm); | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, | ||
| 1247 | u64 size) { | ||
| 1248 | // Validate the address/size. | ||
| 1249 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | ||
| 1250 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 1251 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 1252 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 1253 | |||
| 1254 | // Get the current process. | ||
| 1255 | auto& process = *system.Kernel().CurrentProcess(); | ||
| 1256 | auto& page_table = process.PageTable(); | ||
| 1257 | |||
| 1258 | // Get the shared memory. | ||
| 1259 | KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); | ||
| 1260 | R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); | ||
| 1247 | 1261 | ||
| 1248 | auto shared_memory{ | 1262 | // Verify that the mapping is in range. |
| 1249 | current_process->GetHandleTable().GetObject<KSharedMemory>(shared_memory_handle)}; | 1263 | R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); |
| 1250 | R_UNLESS(shared_memory.IsNotNull(), ResultInvalidHandle); | ||
| 1251 | 1264 | ||
| 1252 | return shared_memory->Map(*current_process, addr, size, | 1265 | // Unmap the shared memory. |
| 1253 | static_cast<KMemoryPermission>(permission_type)); | 1266 | R_TRY(shmem->Unmap(process, address, size)); |
| 1267 | |||
| 1268 | // Remove the shared memory from the process. | ||
| 1269 | process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); | ||
| 1270 | |||
| 1271 | return RESULT_SUCCESS; | ||
| 1254 | } | 1272 | } |
| 1255 | 1273 | ||
| 1256 | static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, | 1274 | static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, |
| 1257 | u32 size, u32 permissions) { | 1275 | u32 size) { |
| 1258 | return MapSharedMemory(system, shared_memory_handle, addr, size, permissions); | 1276 | return UnmapSharedMemory(system, shmem_handle, address, size); |
| 1259 | } | 1277 | } |
| 1260 | 1278 | ||
| 1261 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, | 1279 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, |
| @@ -2297,7 +2315,7 @@ static const FunctionDef SVC_Table_32[] = { | |||
| 2297 | {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, | 2315 | {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, |
| 2298 | {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, | 2316 | {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, |
| 2299 | {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, | 2317 | {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, |
| 2300 | {0x14, nullptr, "UnmapSharedMemory32"}, | 2318 | {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"}, |
| 2301 | {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, | 2319 | {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, |
| 2302 | {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, | 2320 | {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, |
| 2303 | {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, | 2321 | {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, |
| @@ -2492,7 +2510,7 @@ static const FunctionDef SVC_Table_64[] = { | |||
| 2492 | {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, | 2510 | {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, |
| 2493 | {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, | 2511 | {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, |
| 2494 | {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, | 2512 | {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, |
| 2495 | {0x14, nullptr, "UnmapSharedMemory"}, | 2513 | {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"}, |
| 2496 | {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, | 2514 | {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, |
| 2497 | {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, | 2515 | {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, |
| 2498 | {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, | 2516 | {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index d3df25d0f..0968987af 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -232,10 +232,11 @@ void SvcWrap64(Core::System& system) { | |||
| 232 | func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); | 232 | func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | template <ResultCode func(Core::System&, u32, u64, u64, u32)> | 235 | // Used by MapSharedMemory |
| 236 | template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)> | ||
| 236 | void SvcWrap64(Core::System& system) { | 237 | void SvcWrap64(Core::System& system) { |
| 237 | FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), | 238 | FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), Param(system, 1), |
| 238 | Param(system, 2), static_cast<u32>(Param(system, 3))) | 239 | Param(system, 2), static_cast<Svc::MemoryPermission>(Param(system, 3))) |
| 239 | .raw); | 240 | .raw); |
| 240 | } | 241 | } |
| 241 | 242 | ||
| @@ -553,6 +554,16 @@ void SvcWrap32(Core::System& system) { | |||
| 553 | FuncReturn(system, retval); | 554 | FuncReturn(system, retval); |
| 554 | } | 555 | } |
| 555 | 556 | ||
| 557 | // Used by MapSharedMemory32 | ||
| 558 | template <ResultCode func(Core::System&, Handle, u32, u32, Svc::MemoryPermission)> | ||
| 559 | void SvcWrap32(Core::System& system) { | ||
| 560 | const u32 retval = | ||
| 561 | func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1)), static_cast<u32>(Param(system, 2)), | ||
| 562 | static_cast<Svc::MemoryPermission>(Param(system, 3))) | ||
| 563 | .raw; | ||
| 564 | FuncReturn(system, retval); | ||
| 565 | } | ||
| 566 | |||
| 556 | // Used by SetThreadCoreMask32 | 567 | // Used by SetThreadCoreMask32 |
| 557 | template <ResultCode func(Core::System&, Handle, s32, u32, u32)> | 568 | template <ResultCode func(Core::System&, Handle, s32, u32, u32)> |
| 558 | void SvcWrap32(Core::System& system) { | 569 | void SvcWrap32(Core::System& system) { |