mirror of
				https://github.com/Atmosphere-NX/Atmosphere-libs.git
				synced 2025-10-31 19:45:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			106 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) Atmosphère-NX
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it
 | |
|  * under the terms and conditions of the GNU General Public License,
 | |
|  * version 2, as published by the Free Software Foundation.
 | |
|  *
 | |
|  * This program is distributed in the hope it will be useful, but WITHOUT
 | |
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | |
|  * more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| #include <mesosphere.hpp>
 | |
| 
 | |
| namespace ams::kern {
 | |
| 
 | |
|     Result KSharedMemory::Initialize(KProcess *owner, size_t size, ams::svc::MemoryPermission own_perm, ams::svc::MemoryPermission rem_perm) {
 | |
|         MESOSPHERE_ASSERT_THIS();
 | |
| 
 | |
|         /* Set members. */
 | |
|         m_owner_process_id = owner->GetId();
 | |
|         m_owner_perm       = own_perm;
 | |
|         m_remote_perm      = rem_perm;
 | |
| 
 | |
|         /* Get the number of pages. */
 | |
|         const size_t num_pages = util::DivideUp(size, PageSize);
 | |
|         MESOSPHERE_ASSERT(num_pages > 0);
 | |
| 
 | |
|         /* Get the resource limit. */
 | |
|         KResourceLimit *reslimit = owner->GetResourceLimit();
 | |
| 
 | |
|         /* Reserve memory for ourselves. */
 | |
|         KScopedResourceReservation memory_reservation(reslimit, ams::svc::LimitableResource_PhysicalMemoryMax, size);
 | |
|         R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
 | |
| 
 | |
|         /* Allocate the memory. */
 | |
|         R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(m_page_group), num_pages, 1, owner->GetAllocateOption()));
 | |
| 
 | |
|         /* Commit our reservation. */
 | |
|         memory_reservation.Commit();
 | |
| 
 | |
|         /* Set our resource limit. */
 | |
|         m_resource_limit = reslimit;
 | |
|         m_resource_limit->Open();
 | |
| 
 | |
|         /* Mark initialized. */
 | |
|         m_is_initialized = true;
 | |
| 
 | |
|         /* Clear all pages in the memory. */
 | |
|         for (const auto &block : m_page_group) {
 | |
|             std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block.GetAddress())), 0, block.GetSize());
 | |
|         }
 | |
| 
 | |
|         R_SUCCEED();
 | |
|     }
 | |
| 
 | |
|     void KSharedMemory::Finalize() {
 | |
|         MESOSPHERE_ASSERT_THIS();
 | |
| 
 | |
|         /* Get the number of pages. */
 | |
|         const size_t num_pages = m_page_group.GetNumPages();
 | |
|         const size_t size      = num_pages * PageSize;
 | |
| 
 | |
|         /* Close and finalize the page group. */
 | |
|         m_page_group.Close();
 | |
|         m_page_group.Finalize();
 | |
| 
 | |
|         /* Release the memory reservation. */
 | |
|         m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, size);
 | |
|         m_resource_limit->Close();
 | |
|     }
 | |
| 
 | |
|     Result KSharedMemory::Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm) {
 | |
|         MESOSPHERE_ASSERT_THIS();
 | |
| 
 | |
|         /* Validate the size. */
 | |
|         R_UNLESS(m_page_group.GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize());
 | |
| 
 | |
|         /* Validate the permission. */
 | |
|         const ams::svc::MemoryPermission test_perm = (process->GetId() == m_owner_process_id) ? m_owner_perm : m_remote_perm;
 | |
|         if (test_perm == ams::svc::MemoryPermission_DontCare) {
 | |
|             MESOSPHERE_ASSERT(map_perm == ams::svc::MemoryPermission_Read || map_perm == ams::svc::MemoryPermission_ReadWrite);
 | |
|         } else {
 | |
|             R_UNLESS(map_perm == test_perm, svc::ResultInvalidNewMemoryPermission());
 | |
|         }
 | |
| 
 | |
|         /* Map the memory. */
 | |
|         R_RETURN(table->MapPageGroup(address, m_page_group, KMemoryState_Shared, ConvertToKMemoryPermission(map_perm)));
 | |
|     }
 | |
| 
 | |
|     Result KSharedMemory::Unmap(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process) {
 | |
|         MESOSPHERE_ASSERT_THIS();
 | |
|         MESOSPHERE_UNUSED(process);
 | |
| 
 | |
|         /* Validate the size. */
 | |
|         R_UNLESS(m_page_group.GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize());
 | |
| 
 | |
|         /* Unmap the memory. */
 | |
|         R_RETURN(table->UnmapPageGroup(address, m_page_group, KMemoryState_Shared));
 | |
|     }
 | |
| 
 | |
| }
 |