2020-07-22 10:50:19 +01:00
|
|
|
/*
|
2021-10-04 20:59:10 +01:00
|
|
|
* Copyright (c) Atmosphère-NX
|
2020-07-22 10:50:19 +01:00
|
|
|
*
|
|
|
|
* 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. */
|
2020-12-18 01:18:47 +00:00
|
|
|
m_owner_process_id = owner->GetId();
|
|
|
|
m_owner_perm = own_perm;
|
|
|
|
m_remote_perm = rem_perm;
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* 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. */
|
2024-03-28 09:17:38 +00:00
|
|
|
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(m_page_group), num_pages, 1, owner->GetAllocateOption()));
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* Commit our reservation. */
|
|
|
|
memory_reservation.Commit();
|
|
|
|
|
|
|
|
/* Set our resource limit. */
|
2020-12-18 01:18:47 +00:00
|
|
|
m_resource_limit = reslimit;
|
|
|
|
m_resource_limit->Open();
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* Mark initialized. */
|
2020-12-18 01:18:47 +00:00
|
|
|
m_is_initialized = true;
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* Clear all pages in the memory. */
|
2020-12-18 01:18:47 +00:00
|
|
|
for (const auto &block : m_page_group) {
|
2021-09-18 08:11:10 +01:00
|
|
|
std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block.GetAddress())), 0, block.GetSize());
|
2020-07-22 10:50:19 +01:00
|
|
|
}
|
|
|
|
|
2022-02-14 22:45:32 +00:00
|
|
|
R_SUCCEED();
|
2020-07-22 10:50:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void KSharedMemory::Finalize() {
|
|
|
|
MESOSPHERE_ASSERT_THIS();
|
|
|
|
|
|
|
|
/* Get the number of pages. */
|
2020-12-18 01:18:47 +00:00
|
|
|
const size_t num_pages = m_page_group.GetNumPages();
|
2020-07-22 10:50:19 +01:00
|
|
|
const size_t size = num_pages * PageSize;
|
|
|
|
|
|
|
|
/* Close and finalize the page group. */
|
2020-12-18 01:18:47 +00:00
|
|
|
m_page_group.Close();
|
|
|
|
m_page_group.Finalize();
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* Release the memory reservation. */
|
2020-12-18 01:18:47 +00:00
|
|
|
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, size);
|
|
|
|
m_resource_limit->Close();
|
2020-07-22 10:50:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Result KSharedMemory::Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm) {
|
|
|
|
MESOSPHERE_ASSERT_THIS();
|
|
|
|
|
|
|
|
/* Validate the size. */
|
2020-12-18 01:18:47 +00:00
|
|
|
R_UNLESS(m_page_group.GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize());
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* Validate the permission. */
|
2020-12-18 01:18:47 +00:00
|
|
|
const ams::svc::MemoryPermission test_perm = (process->GetId() == m_owner_process_id) ? m_owner_perm : m_remote_perm;
|
2020-07-22 10:50:19 +01:00
|
|
|
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. */
|
2022-02-14 22:45:32 +00:00
|
|
|
R_RETURN(table->MapPageGroup(address, m_page_group, KMemoryState_Shared, ConvertToKMemoryPermission(map_perm)));
|
2020-07-22 10:50:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Result KSharedMemory::Unmap(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process) {
|
|
|
|
MESOSPHERE_ASSERT_THIS();
|
2020-08-17 22:20:24 +01:00
|
|
|
MESOSPHERE_UNUSED(process);
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* Validate the size. */
|
2020-12-18 01:18:47 +00:00
|
|
|
R_UNLESS(m_page_group.GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize());
|
2020-07-22 10:50:19 +01:00
|
|
|
|
|
|
|
/* Unmap the memory. */
|
2022-02-14 22:45:32 +00:00
|
|
|
R_RETURN(table->UnmapPageGroup(address, m_page_group, KMemoryState_Shared));
|
2020-07-22 10:50:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|