diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/k_code_memory.cpp | 28 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.cpp | 111 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.h | 5 |
3 files changed, 118 insertions, 26 deletions
diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index fd3cbfd94..4ae40ec8e 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp | |||
| @@ -27,23 +27,18 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr | |||
| 27 | auto& page_table = m_owner->PageTable(); | 27 | auto& page_table = m_owner->PageTable(); |
| 28 | 28 | ||
| 29 | // Construct the page group. | 29 | // Construct the page group. |
| 30 | m_page_group = | 30 | m_page_group = {}; |
| 31 | KPageLinkedList(page_table.GetPhysicalAddr(addr), Common::DivideUp(size, PageSize)); | ||
| 32 | 31 | ||
| 33 | // Lock the memory. | 32 | // Lock the memory. |
| 34 | R_TRY(page_table.LockForCodeMemory(addr, size)) | 33 | R_TRY(page_table.LockForCodeMemory(&m_page_group, addr, size)) |
| 35 | 34 | ||
| 36 | // Clear the memory. | 35 | // Clear the memory. |
| 37 | // | 36 | for (const auto& block : m_page_group.Nodes()) { |
| 38 | // FIXME: this ends up clobbering address ranges outside the scope of the mapping within | 37 | std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); |
| 39 | // guest memory, and is not specifically required if the guest program is correctly | 38 | } |
| 40 | // written, so disable until this is further investigated. | ||
| 41 | // | ||
| 42 | // for (const auto& block : m_page_group.Nodes()) { | ||
| 43 | // std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); | ||
| 44 | // } | ||
| 45 | 39 | ||
| 46 | // Set remaining tracking members. | 40 | // Set remaining tracking members. |
| 41 | m_owner->Open(); | ||
| 47 | m_address = addr; | 42 | m_address = addr; |
| 48 | m_is_initialized = true; | 43 | m_is_initialized = true; |
| 49 | m_is_owner_mapped = false; | 44 | m_is_owner_mapped = false; |
| @@ -57,8 +52,14 @@ void KCodeMemory::Finalize() { | |||
| 57 | // Unlock. | 52 | // Unlock. |
| 58 | if (!m_is_mapped && !m_is_owner_mapped) { | 53 | if (!m_is_mapped && !m_is_owner_mapped) { |
| 59 | const size_t size = m_page_group.GetNumPages() * PageSize; | 54 | const size_t size = m_page_group.GetNumPages() * PageSize; |
| 60 | m_owner->PageTable().UnlockForCodeMemory(m_address, size); | 55 | m_owner->PageTable().UnlockForCodeMemory(m_address, size, m_page_group); |
| 61 | } | 56 | } |
| 57 | |||
| 58 | // Close the page group. | ||
| 59 | m_page_group = {}; | ||
| 60 | |||
| 61 | // Close our reference to our owner. | ||
| 62 | m_owner->Close(); | ||
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | ResultCode KCodeMemory::Map(VAddr address, size_t size) { | 65 | ResultCode KCodeMemory::Map(VAddr address, size_t size) { |
| @@ -118,7 +119,8 @@ ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermis | |||
| 118 | k_perm = KMemoryPermission::UserReadExecute; | 119 | k_perm = KMemoryPermission::UserReadExecute; |
| 119 | break; | 120 | break; |
| 120 | default: | 121 | default: |
| 121 | break; | 122 | // Already validated by ControlCodeMemory svc |
| 123 | UNREACHABLE(); | ||
| 122 | } | 124 | } |
| 123 | 125 | ||
| 124 | // Map the memory. | 126 | // Map the memory. |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index b38ef333b..68867a2bb 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -542,6 +542,95 @@ ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num | |||
| 542 | return ResultSuccess; | 542 | return ResultSuccess; |
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | bool KPageTable::IsValidPageGroup(const KPageLinkedList& pg_ll, VAddr addr, size_t num_pages) { | ||
| 546 | ASSERT(this->IsLockedByCurrentThread()); | ||
| 547 | |||
| 548 | const size_t size = num_pages * PageSize; | ||
| 549 | const auto& pg = pg_ll.Nodes(); | ||
| 550 | const auto& memory_layout = system.Kernel().MemoryLayout(); | ||
| 551 | |||
| 552 | // Empty groups are necessarily invalid. | ||
| 553 | if (pg.empty()) { | ||
| 554 | return false; | ||
| 555 | } | ||
| 556 | |||
| 557 | // We're going to validate that the group we'd expect is the group we see. | ||
| 558 | auto cur_it = pg.begin(); | ||
| 559 | PAddr cur_block_address = cur_it->GetAddress(); | ||
| 560 | size_t cur_block_pages = cur_it->GetNumPages(); | ||
| 561 | |||
| 562 | auto UpdateCurrentIterator = [&]() { | ||
| 563 | if (cur_block_pages == 0) { | ||
| 564 | if ((++cur_it) == pg.end()) { | ||
| 565 | return false; | ||
| 566 | } | ||
| 567 | |||
| 568 | cur_block_address = cur_it->GetAddress(); | ||
| 569 | cur_block_pages = cur_it->GetNumPages(); | ||
| 570 | } | ||
| 571 | return true; | ||
| 572 | }; | ||
| 573 | |||
| 574 | // Begin traversal. | ||
| 575 | Common::PageTable::TraversalContext context; | ||
| 576 | Common::PageTable::TraversalEntry next_entry; | ||
| 577 | if (!page_table_impl.BeginTraversal(next_entry, context, addr)) { | ||
| 578 | return false; | ||
| 579 | } | ||
| 580 | |||
| 581 | // Prepare tracking variables. | ||
| 582 | PAddr cur_addr = next_entry.phys_addr; | ||
| 583 | size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1)); | ||
| 584 | size_t tot_size = cur_size; | ||
| 585 | |||
| 586 | // Iterate, comparing expected to actual. | ||
| 587 | while (tot_size < size) { | ||
| 588 | if (!page_table_impl.ContinueTraversal(next_entry, context)) { | ||
| 589 | return false; | ||
| 590 | } | ||
| 591 | |||
| 592 | if (next_entry.phys_addr != (cur_addr + cur_size)) { | ||
| 593 | const size_t cur_pages = cur_size / PageSize; | ||
| 594 | |||
| 595 | if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) { | ||
| 596 | return false; | ||
| 597 | } | ||
| 598 | |||
| 599 | if (!UpdateCurrentIterator()) { | ||
| 600 | return false; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (cur_block_address != cur_addr || cur_block_pages < cur_pages) { | ||
| 604 | return false; | ||
| 605 | } | ||
| 606 | |||
| 607 | cur_block_address += cur_size; | ||
| 608 | cur_block_pages -= cur_pages; | ||
| 609 | cur_addr = next_entry.phys_addr; | ||
| 610 | cur_size = next_entry.block_size; | ||
| 611 | } else { | ||
| 612 | cur_size += next_entry.block_size; | ||
| 613 | } | ||
| 614 | |||
| 615 | tot_size += next_entry.block_size; | ||
| 616 | } | ||
| 617 | |||
| 618 | // Ensure we compare the right amount for the last block. | ||
| 619 | if (tot_size > size) { | ||
| 620 | cur_size -= (tot_size - size); | ||
| 621 | } | ||
| 622 | |||
| 623 | if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) { | ||
| 624 | return false; | ||
| 625 | } | ||
| 626 | |||
| 627 | if (!UpdateCurrentIterator()) { | ||
| 628 | return false; | ||
| 629 | } | ||
| 630 | |||
| 631 | return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize); | ||
| 632 | } | ||
| 633 | |||
| 545 | ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, | 634 | ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, |
| 546 | KPageTable& src_page_table, VAddr src_addr) { | 635 | KPageTable& src_page_table, VAddr src_addr) { |
| 547 | KScopedLightLock lk(general_lock); | 636 | KScopedLightLock lk(general_lock); |
| @@ -1687,22 +1776,22 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) | |||
| 1687 | return ResultSuccess; | 1776 | return ResultSuccess; |
| 1688 | } | 1777 | } |
| 1689 | 1778 | ||
| 1690 | ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { | 1779 | ResultCode KPageTable::LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size) { |
| 1691 | return this->LockMemoryAndOpen( | 1780 | return this->LockMemoryAndOpen( |
| 1692 | nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | 1781 | out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory, |
| 1693 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, KMemoryPermission::UserReadWrite, | 1782 | KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All, |
| 1694 | KMemoryAttribute::All, KMemoryAttribute::None, | 1783 | KMemoryAttribute::None, |
| 1695 | static_cast<KMemoryPermission>(KMemoryPermission::NotMapped | | 1784 | static_cast<KMemoryPermission>(KMemoryPermission::NotMapped | |
| 1696 | KMemoryPermission::KernelReadWrite), | 1785 | KMemoryPermission::KernelReadWrite), |
| 1697 | KMemoryAttribute::Locked); | 1786 | KMemoryAttribute::Locked); |
| 1698 | } | 1787 | } |
| 1699 | 1788 | ||
| 1700 | ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { | 1789 | ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size, |
| 1701 | return this->UnlockMemory(addr, size, KMemoryState::FlagCanCodeMemory, | 1790 | const KPageLinkedList& pg) { |
| 1702 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, | 1791 | return this->UnlockMemory( |
| 1703 | KMemoryPermission::None, KMemoryAttribute::All, | 1792 | addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory, |
| 1704 | KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, | 1793 | KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All, |
| 1705 | KMemoryAttribute::Locked, nullptr); | 1794 | KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg); |
| 1706 | } | 1795 | } |
| 1707 | 1796 | ||
| 1708 | ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { | 1797 | ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { |
| @@ -2125,7 +2214,7 @@ ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_ | |||
| 2125 | 2214 | ||
| 2126 | // Check the page group. | 2215 | // Check the page group. |
| 2127 | if (pg != nullptr) { | 2216 | if (pg != nullptr) { |
| 2128 | UNIMPLEMENTED_MSG("PageGroup support is unimplemented!"); | 2217 | R_UNLESS(this->IsValidPageGroup(*pg, addr, num_pages), ResultInvalidMemoryRegion); |
| 2129 | } | 2218 | } |
| 2130 | 2219 | ||
| 2131 | // Decide on new perm and attr. | 2220 | // Decide on new perm and attr. |
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 52a93ce86..6312eb682 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -72,8 +72,8 @@ public: | |||
| 72 | KMemoryPermission perm, PAddr map_addr = 0); | 72 | KMemoryPermission perm, PAddr map_addr = 0); |
| 73 | ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); | 73 | ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); |
| 74 | ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); | 74 | ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); |
| 75 | ResultCode LockForCodeMemory(VAddr addr, std::size_t size); | 75 | ResultCode LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size); |
| 76 | ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size); | 76 | ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size, const KPageLinkedList& pg); |
| 77 | ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages, | 77 | ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages, |
| 78 | KMemoryState state_mask, KMemoryState state, | 78 | KMemoryState state_mask, KMemoryState state, |
| 79 | KMemoryPermission perm_mask, KMemoryPermission perm, | 79 | KMemoryPermission perm_mask, KMemoryPermission perm, |
| @@ -178,6 +178,7 @@ private: | |||
| 178 | const KPageLinkedList* pg); | 178 | const KPageLinkedList* pg); |
| 179 | 179 | ||
| 180 | ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages); | 180 | ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages); |
| 181 | bool IsValidPageGroup(const KPageLinkedList& pg, VAddr addr, size_t num_pages); | ||
| 181 | 182 | ||
| 182 | bool IsLockedByCurrentThread() const { | 183 | bool IsLockedByCurrentThread() const { |
| 183 | return general_lock.IsLockedByCurrentThread(); | 184 | return general_lock.IsLockedByCurrentThread(); |