mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 01:26:34 +00:00
kern/svc: implement IoPool/Region svc support
This commit is contained in:
parent
30514c0e2c
commit
29940e1a82
24 changed files with 944 additions and 301 deletions
|
@ -78,8 +78,7 @@
|
|||
#include <mesosphere/kern_select_debug.hpp>
|
||||
#include <mesosphere/kern_k_process.hpp>
|
||||
#include <mesosphere/kern_k_resource_limit.hpp>
|
||||
#include <mesosphere/kern_k_alpha.hpp>
|
||||
#include <mesosphere/kern_k_beta.hpp>
|
||||
#include <mesosphere/kern_k_io_pool.hpp>
|
||||
|
||||
/* More Miscellaneous objects. */
|
||||
#include <mesosphere/kern_k_object_name.hpp>
|
||||
|
|
|
@ -96,6 +96,14 @@ namespace ams::kern::arch::arm64 {
|
|||
return m_page_table.MapIo(phys_addr, size, perm);
|
||||
}
|
||||
|
||||
Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) {
|
||||
return m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm);
|
||||
}
|
||||
|
||||
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) {
|
||||
return m_page_table.UnmapIoRegion(dst_address, phys_addr, size);
|
||||
}
|
||||
|
||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
|
||||
return m_page_table.MapStatic(phys_addr, size, perm);
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ namespace ams::kern::init {
|
|||
size_t num_KObjectName;
|
||||
size_t num_KResourceLimit;
|
||||
size_t num_KDebug;
|
||||
size_t num_KAlpha;
|
||||
size_t num_KBeta;
|
||||
size_t num_KIoPool;
|
||||
size_t num_KIoRegion;
|
||||
};
|
||||
|
||||
NOINLINE void InitializeSlabResourceCounts();
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_auto_object.hpp>
|
||||
#include <mesosphere/kern_slab_helpers.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KAlpha final : public KAutoObjectWithSlabHeapAndContainer<KAlpha, KAutoObjectWithList> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KAlpha, KAutoObject);
|
||||
private:
|
||||
/* NOTE: Official KAlpha has size 0x50, corresponding to 0x20 bytes of fields. */
|
||||
/* TODO: Add these fields, if KAlpha is ever instantiable in the NX kernel. */
|
||||
public:
|
||||
explicit KAlpha() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* virtual void Finalize() override; */
|
||||
|
||||
virtual bool IsInitialized() const override { return false /* TODO */; }
|
||||
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
|
||||
};
|
||||
|
||||
}
|
|
@ -110,10 +110,8 @@ namespace ams::kern {
|
|||
KDeviceAddressSpace,
|
||||
KSessionRequest,
|
||||
KCodeMemory,
|
||||
|
||||
/* NOTE: True order for these has not been determined yet. */
|
||||
KAlpha,
|
||||
KBeta,
|
||||
KIoPool,
|
||||
KIoRegion,
|
||||
|
||||
FinalClassesEnd = FinalClassesStart + NumFinalClasses,
|
||||
};
|
||||
|
|
|
@ -17,30 +17,34 @@
|
|||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_auto_object.hpp>
|
||||
#include <mesosphere/kern_slab_helpers.hpp>
|
||||
#include <mesosphere/kern_k_io_region.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KProcess;
|
||||
|
||||
class KBeta final : public KAutoObjectWithSlabHeapAndContainer<KBeta, KAutoObjectWithList> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KBeta, KAutoObject);
|
||||
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
||||
private:
|
||||
friend class KProcess;
|
||||
using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_pool_list_node>::ListType;
|
||||
private:
|
||||
/* NOTE: Official KBeta has size 0x88, corresponding to 0x58 bytes of fields. */
|
||||
/* TODO: Add these fields, if KBeta is ever instantiable in the NX kernel. */
|
||||
util::IntrusiveListNode m_process_list_node;
|
||||
KLightLock m_lock;
|
||||
IoRegionList m_io_region_list;
|
||||
ams::svc::IoPoolType m_pool_type;
|
||||
bool m_is_initialized;
|
||||
public:
|
||||
explicit KBeta()
|
||||
: m_process_list_node()
|
||||
{
|
||||
static bool IsValidIoPoolType(ams::svc::IoPoolType pool_type);
|
||||
public:
|
||||
explicit KIoPool() : m_lock(), m_io_region_list(), m_is_initialized(false) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* virtual void Finalize() override; */
|
||||
Result Initialize(ams::svc::IoPoolType pool_type);
|
||||
virtual void Finalize() override;
|
||||
|
||||
virtual bool IsInitialized() const override { return false /* TODO */; }
|
||||
virtual bool IsInitialized() const override { return m_is_initialized; }
|
||||
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
|
||||
|
||||
Result AddIoRegion(KIoRegion *region);
|
||||
void RemoveIoRegion(KIoRegion *region);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_auto_object.hpp>
|
||||
#include <mesosphere/kern_slab_helpers.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KProcess;
|
||||
class KIoPool;
|
||||
|
||||
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
|
||||
private:
|
||||
friend class KProcess;
|
||||
friend class KIoPool;
|
||||
private:
|
||||
KLightLock m_lock;
|
||||
KIoPool *m_pool;
|
||||
KPhysicalAddress m_physical_address;
|
||||
size_t m_size;
|
||||
ams::svc::MemoryMapping m_mapping;
|
||||
ams::svc::MemoryPermission m_perm;
|
||||
bool m_is_initialized;
|
||||
bool m_is_mapped;
|
||||
util::IntrusiveListNode m_process_list_node;
|
||||
util::IntrusiveListNode m_pool_list_node;
|
||||
public:
|
||||
explicit KIoRegion()
|
||||
: m_lock(), m_pool(nullptr), m_is_initialized(false), m_process_list_node(), m_pool_list_node()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result Initialize(KIoPool *pool, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
|
||||
virtual void Finalize() override;
|
||||
|
||||
virtual bool IsInitialized() const override { return m_is_initialized; }
|
||||
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
|
||||
|
||||
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
|
||||
Result Unmap(KProcessAddress address, size_t size);
|
||||
|
||||
bool Overlaps(KPhysicalAddress address, size_t size) const {
|
||||
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
||||
ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||
};
|
||||
|
||||
}
|
|
@ -339,6 +339,8 @@ namespace ams::kern {
|
|||
Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||
Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
|
||||
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size);
|
||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <mesosphere/kern_k_thread.hpp>
|
||||
#include <mesosphere/kern_k_thread_local_page.hpp>
|
||||
#include <mesosphere/kern_k_shared_memory_info.hpp>
|
||||
#include <mesosphere/kern_k_beta.hpp>
|
||||
#include <mesosphere/kern_k_io_region.hpp>
|
||||
#include <mesosphere/kern_k_worker_task.hpp>
|
||||
#include <mesosphere/kern_select_page_table.hpp>
|
||||
#include <mesosphere/kern_k_condition_variable.hpp>
|
||||
|
@ -53,7 +53,7 @@ namespace ams::kern {
|
|||
static constexpr size_t AslrAlignment = KernelAslrAlignment;
|
||||
private:
|
||||
using SharedMemoryInfoList = util::IntrusiveListBaseTraits<KSharedMemoryInfo>::ListType;
|
||||
using BetaList = util::IntrusiveListMemberTraits<&KBeta::m_process_list_node>::ListType;
|
||||
using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_process_list_node>::ListType;
|
||||
using TLPTree = util::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
|
||||
using TLPIterator = TLPTree::iterator;
|
||||
private:
|
||||
|
@ -96,7 +96,7 @@ namespace ams::kern {
|
|||
KThread *m_exception_thread{};
|
||||
ThreadList m_thread_list{};
|
||||
SharedMemoryInfoList m_shared_memory_list{};
|
||||
BetaList m_beta_list{};
|
||||
IoRegionList m_io_region_list{};
|
||||
bool m_is_suspended{};
|
||||
bool m_is_immortal{};
|
||||
bool m_is_jit_debug{};
|
||||
|
@ -275,6 +275,9 @@ namespace ams::kern {
|
|||
Result AddSharedMemory(KSharedMemory *shmem, KProcessAddress address, size_t size);
|
||||
void RemoveSharedMemory(KSharedMemory *shmem, KProcessAddress address, size_t size);
|
||||
|
||||
void AddIoRegion(KIoRegion *io_region);
|
||||
void RemoveIoRegion(KIoRegion *io_region);
|
||||
|
||||
Result CreateThreadLocalRegion(KProcessAddress *out);
|
||||
Result DeleteThreadLocalRegion(KProcessAddress addr);
|
||||
void *GetThreadLocalRegionPointer(KProcessAddress addr);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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/>.
|
||||
*/
|
||||
|
||||
constexpr IoRegionExtents g_io_region_extents[4] = {
|
||||
{ KPhysicalAddress(0x12000000), 224_MB }, /* PCIE_A2 */
|
||||
{ Null<KPhysicalAddress>, 0 },
|
||||
{ Null<KPhysicalAddress>, 0 },
|
||||
{ Null<KPhysicalAddress>, 0 },
|
||||
};
|
||||
|
||||
constexpr bool IsValidIoPoolTypeImpl(ams::svc::IoPoolType pool_type) {
|
||||
return pool_type == ams::svc::IoPoolType_PcieA2;
|
||||
}
|
|
@ -39,8 +39,8 @@ namespace ams::kern::init {
|
|||
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \
|
||||
HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||
HANDLER(KAlpha, (SLAB_COUNT(KAlpha)), ## __VA_ARGS__) \
|
||||
HANDLER(KBeta, (SLAB_COUNT(KBeta)), ## __VA_ARGS__)
|
||||
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
|
||||
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__)
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -69,8 +69,8 @@ namespace ams::kern::init {
|
|||
constexpr size_t SlabCountKObjectName = 7;
|
||||
constexpr size_t SlabCountKResourceLimit = 5;
|
||||
constexpr size_t SlabCountKDebug = cpu::NumCores;
|
||||
constexpr size_t SlabCountKAlpha = 1;
|
||||
constexpr size_t SlabCountKBeta = 6;
|
||||
constexpr size_t SlabCountKIoPool = 1;
|
||||
constexpr size_t SlabCountKIoRegion = 6;
|
||||
|
||||
constexpr size_t SlabCountExtraKThread = 160;
|
||||
|
||||
|
@ -97,8 +97,8 @@ namespace ams::kern::init {
|
|||
.num_KObjectName = SlabCountKObjectName,
|
||||
.num_KResourceLimit = SlabCountKResourceLimit,
|
||||
.num_KDebug = SlabCountKDebug,
|
||||
.num_KAlpha = SlabCountKAlpha,
|
||||
.num_KBeta = SlabCountKBeta,
|
||||
.num_KIoPool = SlabCountKIoPool,
|
||||
.num_KIoRegion = SlabCountKIoRegion,
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -346,8 +346,8 @@ namespace ams::kern::KDumpObject {
|
|||
DUMP_KSLABOBJ(KEventInfo);
|
||||
DUMP_KSLABOBJ(KSessionRequest);
|
||||
DUMP_KSLABOBJ(KResourceLimit);
|
||||
DUMP_KSLABOBJ(KAlpha);
|
||||
DUMP_KSLABOBJ(KBeta);
|
||||
DUMP_KSLABOBJ(KIoPool);
|
||||
DUMP_KSLABOBJ(KIoRegion);
|
||||
|
||||
#undef DUMP_KSLABOBJ
|
||||
|
||||
|
|
129
libraries/libmesosphere/source/kern_k_io_pool.cpp
Normal file
129
libraries/libmesosphere/source/kern_k_io_pool.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit KLightLock g_io_pool_lock;
|
||||
constinit bool g_pool_used[ams::svc::IoPoolType_Count];
|
||||
|
||||
struct IoRegionExtents {
|
||||
KPhysicalAddress address;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
|
||||
|
||||
#include "board/nintendo/nx/kern_k_io_pool.board.nintendo_nx.inc"
|
||||
|
||||
#elif defined(AMS_SVC_IO_POOL_NOT_SUPPORTED)
|
||||
|
||||
#include "kern_k_io_pool.unsupported.inc"
|
||||
|
||||
#else
|
||||
|
||||
#error "Unknown context for IoPoolType!"
|
||||
|
||||
#endif
|
||||
|
||||
constexpr bool IsValidIoRegionImpl(ams::svc::IoPoolType pool_type, KPhysicalAddress address, size_t size) {
|
||||
/* NOTE: It seems likely this depends on pool type, but this isn't confirmable as of now. */
|
||||
MESOSPHERE_UNUSED(pool_type);
|
||||
|
||||
/* Check if the address/size falls within any allowable extents. */
|
||||
for (const auto &extents : g_io_region_extents) {
|
||||
if (extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool KIoPool::IsValidIoPoolType(ams::svc::IoPoolType pool_type) {
|
||||
return IsValidIoPoolTypeImpl(pool_type);
|
||||
}
|
||||
|
||||
Result KIoPool::Initialize(ams::svc::IoPoolType pool_type) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Register the pool type. */
|
||||
{
|
||||
/* Lock the pool used table. */
|
||||
KScopedLightLock lk(g_io_pool_lock);
|
||||
|
||||
/* Check that the pool isn't already used. */
|
||||
R_UNLESS(!g_pool_used[pool_type], svc::ResultBusy());
|
||||
|
||||
/* Set the pool as used. */
|
||||
g_pool_used[pool_type] = true;
|
||||
}
|
||||
|
||||
/* Set our fields. */
|
||||
m_pool_type = pool_type;
|
||||
m_is_initialized = true;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void KIoPool::Finalize() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Lock the pool used table. */
|
||||
KScopedLightLock lk(g_io_pool_lock);
|
||||
|
||||
/* Check that the pool is used. */
|
||||
MESOSPHERE_ASSERT(g_pool_used[m_pool_type]);
|
||||
|
||||
/* Set the pool as unused. */
|
||||
g_pool_used[m_pool_type] = false;
|
||||
}
|
||||
|
||||
Result KIoPool::AddIoRegion(KIoRegion *new_region) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Check that the region is allowed. */
|
||||
R_UNLESS(IsValidIoRegionImpl(m_pool_type, new_region->GetAddress(), new_region->GetSize()), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Lock ourselves. */
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
/* Check that the desired range isn't already in our pool. */
|
||||
for (const auto ®ion : m_io_region_list) {
|
||||
R_UNLESS(!region.Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||
}
|
||||
|
||||
/* Add the region to our pool. */
|
||||
m_io_region_list.push_back(*new_region);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void KIoPool::RemoveIoRegion(KIoRegion *region) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Lock ourselves. */
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
/* Remove the region from our list. */
|
||||
m_io_region_list.erase(m_io_region_list.iterator_to(*region));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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/>.
|
||||
*/
|
||||
|
||||
constexpr IoRegionExtents g_io_region_extents[4] = {
|
||||
{ Null<KPhysicalAddress>, 0 },
|
||||
{ Null<KPhysicalAddress>, 0 },
|
||||
{ Null<KPhysicalAddress>, 0 },
|
||||
{ Null<KPhysicalAddress>, 0 },
|
||||
};
|
||||
|
||||
constexpr bool IsValidIoPoolTypeImpl(ams::svc::IoPoolType pool_type) {
|
||||
MESOSPHERE_UNUSED(pool_type);
|
||||
return false;
|
||||
}
|
99
libraries/libmesosphere/source/kern_k_io_region.cpp
Normal file
99
libraries/libmesosphere/source/kern_k_io_region.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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 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_perm = 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;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
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_perm | map_perm) == m_perm, 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;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
/* Remove ourselves from the current process. */
|
||||
GetCurrentProcess().RemoveIoRegion(this);
|
||||
|
||||
/* Note that we're unmapped. */
|
||||
m_is_mapped = false;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
|
@ -368,10 +368,10 @@ namespace ams::kern {
|
|||
return m_alias_region_start;
|
||||
case KMemoryState_Stack:
|
||||
return m_stack_region_start;
|
||||
case KMemoryState_Io:
|
||||
case KMemoryState_Static:
|
||||
case KMemoryState_ThreadLocal:
|
||||
return m_kernel_map_region_start;
|
||||
case KMemoryState_Io:
|
||||
case KMemoryState_Shared:
|
||||
case KMemoryState_AliasCode:
|
||||
case KMemoryState_AliasCodeData:
|
||||
|
@ -402,10 +402,10 @@ namespace ams::kern {
|
|||
return m_alias_region_end - m_alias_region_start;
|
||||
case KMemoryState_Stack:
|
||||
return m_stack_region_end - m_stack_region_start;
|
||||
case KMemoryState_Io:
|
||||
case KMemoryState_Static:
|
||||
case KMemoryState_ThreadLocal:
|
||||
return m_kernel_map_region_end - m_kernel_map_region_start;
|
||||
case KMemoryState_Io:
|
||||
case KMemoryState_Shared:
|
||||
case KMemoryState_AliasCode:
|
||||
case KMemoryState_AliasCodeData:
|
||||
|
@ -1823,10 +1823,12 @@ namespace ams::kern {
|
|||
const KPhysicalAddress last = phys_addr + size - 1;
|
||||
|
||||
/* Get region extents. */
|
||||
const KProcessAddress region_start = this->GetRegionAddress(KMemoryState_Io);
|
||||
const size_t region_size = this->GetRegionSize(KMemoryState_Io);
|
||||
const KProcessAddress region_start = m_kernel_map_region_start;
|
||||
const size_t region_size = m_kernel_map_region_end - m_kernel_map_region_start;
|
||||
const size_t region_num_pages = region_size / PageSize;
|
||||
|
||||
MESOSPHERE_ASSERT(this->CanContain(region_start, region_size, KMemoryState_Io));
|
||||
|
||||
/* Locate the memory region. */
|
||||
const KMemoryRegion *region = KMemoryLayout::Find(phys_addr);
|
||||
R_UNLESS(region != nullptr, svc::ResultInvalidAddress());
|
||||
|
@ -1906,6 +1908,87 @@ namespace ams::kern {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPageTableBase::MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission svc_perm) {
|
||||
const size_t num_pages = size / PageSize;
|
||||
|
||||
/* Lock the table. */
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Validate the memory state. */
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_None, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
|
||||
/* Create an update allocator. */
|
||||
Result allocator_result;
|
||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks);
|
||||
R_TRY(allocator_result);
|
||||
|
||||
/* We're going to perform an update, so create a helper. */
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
/* Perform mapping operation. */
|
||||
const KMemoryPermission perm = ConvertToKMemoryPermission(svc_perm);
|
||||
const KPageProperties properties = { perm, mapping == ams::svc::MemoryMapping_IoRegister, mapping == ams::svc::MemoryMapping_Uncached, DisableMergeAttribute_DisableHead };
|
||||
R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
||||
|
||||
/* Update the blocks. */
|
||||
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Io, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
||||
|
||||
/* We successfully mapped the pages. */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) {
|
||||
const size_t num_pages = size / PageSize;
|
||||
|
||||
/* Lock the table. */
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Validate the memory state. */
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||
|
||||
/* Validate that the region being unmapped corresponds to the physical range described. */
|
||||
{
|
||||
/* Get the impl. */
|
||||
auto &impl = this->GetImpl();
|
||||
|
||||
/* Begin traversal. */
|
||||
TraversalContext context;
|
||||
TraversalEntry next_entry;
|
||||
MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), dst_address));
|
||||
|
||||
/* Check that the physical region matches. */
|
||||
R_UNLESS(next_entry.phys_addr == phys_addr, svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Iterate. */
|
||||
for (size_t checked_size = next_entry.block_size - (GetInteger(phys_addr) & (next_entry.block_size - 1)); checked_size < size; checked_size += next_entry.block_size) {
|
||||
/* Continue the traversal. */
|
||||
MESOSPHERE_ABORT_UNLESS(impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)));
|
||||
|
||||
/* Check that the physical region matches. */
|
||||
R_UNLESS(next_entry.phys_addr == phys_addr + checked_size, svc::ResultInvalidMemoryRegion());
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an update allocator. */
|
||||
Result allocator_result;
|
||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks);
|
||||
R_TRY(allocator_result);
|
||||
|
||||
/* We're going to perform an update, so create a helper. */
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
/* Perform the unmap. */
|
||||
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||
R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||
|
||||
/* Update the blocks. */
|
||||
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPageTableBase::MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
|
||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||
MESOSPHERE_ASSERT(util::IsAligned(size, PageSize));
|
||||
|
|
|
@ -141,14 +141,14 @@ namespace ams::kern {
|
|||
}
|
||||
}
|
||||
|
||||
/* Close all references to our betas. */
|
||||
/* Close all references to our io regions. */
|
||||
{
|
||||
auto it = m_beta_list.begin();
|
||||
while (it != m_beta_list.end()) {
|
||||
KBeta *beta = std::addressof(*it);
|
||||
it = m_beta_list.erase(it);
|
||||
auto it = m_io_region_list.begin();
|
||||
while (it != m_io_region_list.end()) {
|
||||
KIoRegion *io_region = std::addressof(*it);
|
||||
it = m_io_region_list.erase(it);
|
||||
|
||||
beta->Close();
|
||||
io_region->Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,6 +597,32 @@ namespace ams::kern {
|
|||
shmem->Close();
|
||||
}
|
||||
|
||||
void KProcess::AddIoRegion(KIoRegion *io_region) {
|
||||
/* Lock ourselves, to prevent concurrent access. */
|
||||
KScopedLightLock lk(m_state_lock);
|
||||
|
||||
/* Open a reference to the region. */
|
||||
io_region->Open();
|
||||
|
||||
/* Add the region to our list. */
|
||||
m_io_region_list.push_back(*io_region);
|
||||
|
||||
}
|
||||
|
||||
void KProcess::RemoveIoRegion(KIoRegion *io_region) {
|
||||
/* Remove the region from our list. */
|
||||
{
|
||||
/* Lock ourselves, to prevent concurrent access. */
|
||||
KScopedLightLock lk(m_state_lock);
|
||||
|
||||
/* Remove the region from our list. */
|
||||
m_io_region_list.erase(m_io_region_list.iterator_to(*io_region));
|
||||
}
|
||||
|
||||
/* Close our reference to the io region. */
|
||||
io_region->Close();
|
||||
}
|
||||
|
||||
Result KProcess::CreateThreadLocalRegion(KProcessAddress *out) {
|
||||
KThreadLocalPage *tlp = nullptr;
|
||||
KProcessAddress tlr = Null<KProcessAddress>;
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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::svc {
|
||||
|
||||
/* ============================= Common ============================= */
|
||||
|
||||
namespace {
|
||||
|
||||
Result Unknown39() {
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
|
||||
Result Unknown3A() {
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
|
||||
Result Unknown46() {
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
|
||||
Result Unknown47() {
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================= 64 ABI ============================= */
|
||||
|
||||
Result Unknown3964() {
|
||||
return Unknown39();
|
||||
}
|
||||
|
||||
Result Unknown3A64() {
|
||||
/* NOTE: From official stubs, true API to this is something like Unknown3A(u64 *, u32_or_u64, u64, u64, u64_or_u32, u64_or_u32); */
|
||||
return Unknown3A();
|
||||
}
|
||||
|
||||
Result Unknown4664() {
|
||||
return Unknown46();
|
||||
}
|
||||
|
||||
Result Unknown4764() {
|
||||
return Unknown47();
|
||||
}
|
||||
|
||||
/* ============================= 64From32 ABI ============================= */
|
||||
|
||||
Result Unknown3964From32() {
|
||||
return Unknown39();
|
||||
}
|
||||
|
||||
Result Unknown3A64From32() {
|
||||
return Unknown3A();
|
||||
}
|
||||
|
||||
Result Unknown4664From32() {
|
||||
return Unknown46();
|
||||
}
|
||||
|
||||
Result Unknown4764From32() {
|
||||
return Unknown47();
|
||||
}
|
||||
|
||||
}
|
214
libraries/libmesosphere/source/svc/kern_svc_io_pool.cpp
Normal file
214
libraries/libmesosphere/source/svc/kern_svc_io_pool.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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::svc {
|
||||
|
||||
/* ============================= Common ============================= */
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(AMS_SVC_IO_POOL_NOT_SUPPORTED)
|
||||
constexpr bool IsIoPoolApiSupported = false;
|
||||
#else
|
||||
constexpr bool IsIoPoolApiSupported = true;
|
||||
#endif
|
||||
|
||||
[[maybe_unused]] constexpr bool IsValidIoRegionMapping(ams::svc::MemoryMapping mapping) {
|
||||
switch (mapping) {
|
||||
case ams::svc::MemoryMapping_IoRegister:
|
||||
case ams::svc::MemoryMapping_Uncached:
|
||||
case ams::svc::MemoryMapping_Memory:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] constexpr bool IsValidIoRegionPermission(ams::svc::MemoryPermission perm) {
|
||||
switch (perm) {
|
||||
case ams::svc::MemoryPermission_Read:
|
||||
case ams::svc::MemoryPermission_ReadWrite:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Result CreateIoPool(ams::svc::Handle *out, ams::svc::IoPoolType pool_type) {
|
||||
if constexpr (IsIoPoolApiSupported) {
|
||||
/* Validate that we're allowed to create a pool for the given type. */
|
||||
R_UNLESS(KIoPool::IsValidIoPoolType(pool_type), svc::ResultNotFound());
|
||||
|
||||
/* Create the io pool. */
|
||||
KIoPool *io_pool = KIoPool::Create();
|
||||
R_UNLESS(io_pool != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
/* Ensure the only reference is in the handle table when we're done. */
|
||||
ON_SCOPE_EXIT { io_pool->Close(); };
|
||||
|
||||
/* Initialize the io pool. */
|
||||
R_TRY(io_pool->Initialize(pool_type));
|
||||
|
||||
/* Register the io pool. */
|
||||
KIoPool::Register(io_pool);
|
||||
|
||||
/* Add the io pool to the handle table. */
|
||||
R_TRY(GetCurrentProcess().GetHandleTable().Add(out, io_pool));
|
||||
|
||||
return ResultSuccess();
|
||||
} else {
|
||||
MESOSPHERE_UNUSED(out, pool_type);
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
Result CreateIoRegion(ams::svc::Handle *out, ams::svc::Handle io_pool_handle, uint64_t phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) {
|
||||
if constexpr (IsIoPoolApiSupported) {
|
||||
/* Validate the address/size. */
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(phys_addr, PageSize), svc::ResultInvalidAddress());
|
||||
R_UNLESS((phys_addr < phys_addr + size), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Validate the mapping/permissions. */
|
||||
R_UNLESS(IsValidIoRegionMapping(mapping), svc::ResultInvalidEnumValue());
|
||||
R_UNLESS(IsValidIoRegionPermission(perm), svc::ResultInvalidEnumValue());
|
||||
|
||||
/* Get the current handle table. */
|
||||
auto &handle_table = GetCurrentProcess().GetHandleTable();
|
||||
|
||||
/* Get the io pool. */
|
||||
KScopedAutoObject io_pool = handle_table.GetObject<KIoPool>(io_pool_handle);
|
||||
R_UNLESS(io_pool.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* Create the io region. */
|
||||
KIoRegion *io_region = KIoRegion::Create();
|
||||
R_UNLESS(io_region != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
/* Ensure the only reference is in the handle table when we're done. */
|
||||
ON_SCOPE_EXIT { io_region->Close(); };
|
||||
|
||||
/* Initialize the io region. */
|
||||
R_TRY(io_region->Initialize(io_pool.GetPointerUnsafe(), phys_addr, size, mapping, perm));
|
||||
|
||||
/* Register the io region. */
|
||||
KIoRegion::Register(io_region);
|
||||
|
||||
/* Add the io region to the handle table. */
|
||||
R_TRY(handle_table.Add(out, io_region));
|
||||
|
||||
return ResultSuccess();
|
||||
} else {
|
||||
MESOSPHERE_UNUSED(out, io_pool_handle, phys_addr, size, mapping, perm);
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
Result MapIoRegion(ams::svc::Handle io_region_handle, uintptr_t address, size_t size, ams::svc::MemoryPermission map_perm) {
|
||||
if constexpr (IsIoPoolApiSupported) {
|
||||
/* Validate the address/size. */
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
|
||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Verify that the mapping is in range. */
|
||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Io), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Validate the map permission. */
|
||||
R_UNLESS(IsValidIoRegionPermission(map_perm), svc::ResultInvalidNewMemoryPermission());
|
||||
|
||||
/* Get the io region. */
|
||||
KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(io_region_handle);
|
||||
R_UNLESS(io_region.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* Map the io region. */
|
||||
R_TRY(io_region->Map(address, size, map_perm));
|
||||
|
||||
/* We succeeded. */
|
||||
return ResultSuccess();
|
||||
} else {
|
||||
MESOSPHERE_UNUSED(io_region_handle, address, size, map_perm);
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
Result UnmapIoRegion(ams::svc::Handle io_region_handle, uintptr_t address, size_t size) {
|
||||
if constexpr (IsIoPoolApiSupported) {
|
||||
/* Validate the address/size. */
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
|
||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Verify that the mapping is in range. */
|
||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Io), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Get the io region. */
|
||||
KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(io_region_handle);
|
||||
R_UNLESS(io_region.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* Unmap the io region. */
|
||||
R_TRY(io_region->Unmap(address, size));
|
||||
|
||||
/* We succeeded. */
|
||||
return ResultSuccess();
|
||||
} else {
|
||||
MESOSPHERE_UNUSED(io_region_handle, address, size);
|
||||
return svc::ResultNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================= 64 ABI ============================= */
|
||||
|
||||
Result CreateIoPool64(ams::svc::Handle *out_handle, ams::svc::IoPoolType pool_type) {
|
||||
return CreateIoPool(out_handle, pool_type);
|
||||
}
|
||||
|
||||
Result CreateIoRegion64(ams::svc::Handle *out_handle, ams::svc::Handle io_pool, ams::svc::PhysicalAddress physical_address, ams::svc::Size size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) {
|
||||
return CreateIoRegion(out_handle, io_pool, physical_address, size, mapping, perm);
|
||||
}
|
||||
|
||||
Result MapIoRegion64(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) {
|
||||
return MapIoRegion(io_region, address, size, perm);
|
||||
}
|
||||
|
||||
Result UnmapIoRegion64(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size) {
|
||||
return UnmapIoRegion(io_region, address, size);
|
||||
}
|
||||
|
||||
/* ============================= 64From32 ABI ============================= */
|
||||
|
||||
Result CreateIoPool64From32(ams::svc::Handle *out_handle, ams::svc::IoPoolType pool_type) {
|
||||
return CreateIoPool(out_handle, pool_type);
|
||||
}
|
||||
|
||||
Result CreateIoRegion64From32(ams::svc::Handle *out_handle, ams::svc::Handle io_pool, ams::svc::PhysicalAddress physical_address, ams::svc::Size size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) {
|
||||
return CreateIoRegion(out_handle, io_pool, physical_address, size, mapping, perm);
|
||||
}
|
||||
|
||||
Result MapIoRegion64From32(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) {
|
||||
return MapIoRegion(io_region, address, size, perm);
|
||||
}
|
||||
|
||||
Result UnmapIoRegion64From32(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size) {
|
||||
return UnmapIoRegion(io_region, address, size);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours/svc/svc_types_common.hpp>
|
||||
|
||||
namespace ams::svc::board::nintendo::nx {
|
||||
|
||||
enum IoPoolType : u32 {
|
||||
IoPoolType_PcieA2 = 0, /* NOTE: Name is not official. */
|
||||
|
||||
IoPoolType_Count = 1,
|
||||
};
|
||||
|
||||
}
|
|
@ -85,8 +85,8 @@
|
|||
HANDLER(0x36, void, SynchronizePreemptionState) \
|
||||
HANDLER(0x37, Result, GetResourceLimitPeakValue, OUTPUT(int64_t, out_peak_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
|
||||
\
|
||||
HANDLER(0x39, Result, Unknown39) \
|
||||
HANDLER(0x3A, Result, Unknown3A) \
|
||||
HANDLER(0x39, Result, CreateIoPool, OUTPUT(::ams::svc::Handle, out_handle), INPUT(::ams::svc::IoPoolType, which)) \
|
||||
HANDLER(0x3A, Result, CreateIoRegion, OUTPUT(::ams::svc::Handle, out_handle), INPUT(::ams::svc::Handle, io_pool), INPUT(::ams::svc::PhysicalAddress, physical_address), INPUT(::ams::svc::Size, size), INPUT(::ams::svc::MemoryMapping, mapping), INPUT(::ams::svc::MemoryPermission, perm)) \
|
||||
\
|
||||
HANDLER(0x3C, void, KernelDebug, INPUT(::ams::svc::KernelDebugType, kern_debug_type), INPUT(uint64_t, arg0), INPUT(uint64_t, arg1), INPUT(uint64_t, arg2)) \
|
||||
HANDLER(0x3D, void, ChangeKernelTraceState, INPUT(::ams::svc::KernelTraceState, kern_trace_state)) \
|
||||
|
@ -97,8 +97,8 @@
|
|||
HANDLER(0x43, Result, ReplyAndReceive, OUTPUT(int32_t, out_index), INPTR(::ams::svc::Handle, handles), INPUT(int32_t, num_handles), INPUT(::ams::svc::Handle, reply_target), INPUT(int64_t, timeout_ns)) \
|
||||
HANDLER(0x44, Result, ReplyAndReceiveWithUserBuffer, OUTPUT(int32_t, out_index), INPUT(::ams::svc::Address, message_buffer), INPUT(::ams::svc::Size, message_buffer_size), INPTR(::ams::svc::Handle, handles), INPUT(int32_t, num_handles), INPUT(::ams::svc::Handle, reply_target), INPUT(int64_t, timeout_ns)) \
|
||||
HANDLER(0x45, Result, CreateEvent, OUTPUT(::ams::svc::Handle, out_write_handle), OUTPUT(::ams::svc::Handle, out_read_handle)) \
|
||||
HANDLER(0x46, Result, Unknown46) \
|
||||
HANDLER(0x47, Result, Unknown47) \
|
||||
HANDLER(0x46, Result, MapIoRegion, INPUT(::ams::svc::Handle, io_region), INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size), INPUT(::ams::svc::MemoryPermission, perm)) \
|
||||
HANDLER(0x47, Result, UnmapIoRegion, INPUT(::ams::svc::Handle, io_region), INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \
|
||||
HANDLER(0x48, Result, MapPhysicalMemoryUnsafe, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \
|
||||
HANDLER(0x49, Result, UnmapPhysicalMemoryUnsafe, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \
|
||||
HANDLER(0x4A, Result, SetUnsafeLimit, INPUT(::ams::svc::Size, limit)) \
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/svc/svc_common.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
|
||||
|
||||
#include <vapours/svc/board/nintendo/nx/svc_io_pool_type.hpp>
|
||||
namespace ams::svc {
|
||||
|
||||
using IoPoolType = ::ams::svc::board::nintendo::nx::IoPoolType;
|
||||
using enum ::ams::svc::board::nintendo::nx::IoPoolType;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define AMS_SVC_IO_POOL_NOT_SUPPORTED
|
||||
|
||||
namespace ams::svc {
|
||||
|
||||
enum IoPoolType : u32 {
|
||||
/* Not supported. */
|
||||
IoPoolType_Count = 0,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -23,3 +23,4 @@
|
|||
#include <vapours/svc/svc_types_dd.hpp>
|
||||
#include <vapours/svc/svc_types_dmnt.hpp>
|
||||
#include <vapours/svc/svc_types_priv.hpp>
|
||||
#include <vapours/svc/svc_select_io_pool_type.hpp>
|
||||
|
|
|
@ -117,6 +117,12 @@ namespace ams::svc {
|
|||
MemoryAttribute_Uncached = (1 << 3),
|
||||
};
|
||||
|
||||
enum MemoryMapping : u32 {
|
||||
MemoryMapping_IoRegister = 0,
|
||||
MemoryMapping_Uncached = 1,
|
||||
MemoryMapping_Memory = 2,
|
||||
};
|
||||
|
||||
constexpr inline size_t HeapSizeAlignment = 2_MB;
|
||||
|
||||
struct PageInfo {
|
||||
|
|
Loading…
Reference in a new issue