/* * 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 . */ #include namespace ams::kern { Result KIoRegion::Initialize(KIoPool *pool, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) { MESOSPHERE_ASSERT_THIS(); /* Set fields. */ m_physical_address = phys_addr; m_size = size; m_mapping = mapping; m_permission = perm; m_pool = pool; m_is_mapped = false; /* Add ourselves to our pool. */ R_TRY(m_pool->AddIoRegion(this)); /* Open a reference to our pool. */ m_pool->Open(); /* Mark ourselves as initialized. */ m_is_initialized = true; R_SUCCEED(); } void KIoRegion::Finalize() { /* Remove ourselves from our pool. */ m_pool->RemoveIoRegion(this); /* Close our reference to our pool. */ m_pool->Close(); } Result KIoRegion::Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm) { MESOSPHERE_ASSERT_THIS(); /* Check that the desired perm is allowable. */ R_UNLESS((m_permission | map_perm) == m_permission, svc::ResultInvalidNewMemoryPermission()); /* Check that the size is correct. */ R_UNLESS(size == m_size, svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that we're not already mapped. */ R_UNLESS(!m_is_mapped, svc::ResultInvalidState()); /* Map ourselves. */ R_TRY(GetCurrentProcess().GetPageTable().MapIoRegion(address, m_physical_address, size, m_mapping, map_perm)); /* Add ourselves to the current process. */ GetCurrentProcess().AddIoRegion(this); /* Note that we're mapped. */ m_is_mapped = true; R_SUCCEED(); } Result KIoRegion::Unmap(KProcessAddress address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Check that the size is correct. */ R_UNLESS(size == m_size, svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Unmap ourselves. */ R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size, m_mapping)); /* Remove ourselves from the current process. */ GetCurrentProcess().RemoveIoRegion(this); /* Note that we're unmapped. */ m_is_mapped = false; R_SUCCEED(); } }