mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-27 21:24:11 -04:00
kern: move SecureAppletMemory/KPageBuffer heap into the ResourceRegion
This commit is contained in:
parent
ea82889e6c
commit
5a918f3bc9
21 changed files with 282 additions and 100 deletions
|
@ -29,7 +29,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||
constinit bool g_call_smc_on_panic;
|
||||
|
||||
/* Global variables for secure memory. */
|
||||
constexpr size_t SecureAppletMemorySize = 4_MB;
|
||||
constinit KSpinLock g_secure_applet_lock;
|
||||
constinit bool g_secure_applet_memory_used = false;
|
||||
constinit KVirtualAddress g_secure_applet_memory_address = Null<KVirtualAddress>;
|
||||
|
@ -246,8 +245,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||
|
||||
Result AllocateSecureMemoryForApplet(KVirtualAddress *out, size_t size) {
|
||||
/* Verify that the size is valid. */
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(size <= SecureAppletMemorySize, svc::ResultOutOfMemory());
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(size <= KSystemControl::SecureAppletMemorySize, svc::ResultOutOfMemory());
|
||||
|
||||
/* Disable interrupts and acquire the secure applet lock. */
|
||||
KScopedInterruptDisable di;
|
||||
|
@ -273,7 +272,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
|
||||
/* Verify that the memory being freed is correct. */
|
||||
MESOSPHERE_ABORT_UNLESS(address == g_secure_applet_memory_address);
|
||||
MESOSPHERE_ABORT_UNLESS(size <= SecureAppletMemorySize);
|
||||
MESOSPHERE_ABORT_UNLESS(size <= KSystemControl::SecureAppletMemorySize);
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_used);
|
||||
|
||||
|
@ -451,17 +450,11 @@ namespace ams::kern::board::nintendo::nx {
|
|||
/* Initialize the sleep manager. */
|
||||
KSleepManager::Initialize();
|
||||
|
||||
/* Reserve secure applet memory. */
|
||||
if (GetTargetFirmware() >= TargetFirmware_5_0_0) {
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null<KVirtualAddress>);
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletMemorySize));
|
||||
/* Get the secure applet memory. */
|
||||
const auto &secure_applet_memory = KMemoryLayout::GetSecureAppletMemoryRegion();
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(secure_applet_memory.GetSize() == SecureAppletMemorySize);
|
||||
|
||||
constexpr auto SecureAppletAllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
const KPhysicalAddress secure_applet_memory_phys_addr = Kernel::GetMemoryManager().AllocateAndOpenContinuous(SecureAppletMemorySize / PageSize, 1, SecureAppletAllocateOption);
|
||||
MESOSPHERE_ABORT_UNLESS(secure_applet_memory_phys_addr != Null<KPhysicalAddress>);
|
||||
|
||||
g_secure_applet_memory_address = KMemoryLayout::GetLinearVirtualAddress(secure_applet_memory_phys_addr);
|
||||
}
|
||||
g_secure_applet_memory_address = secure_applet_memory.GetAddress();
|
||||
|
||||
/* Initialize KTrace (and potentially other init). */
|
||||
KSystemControlBase::InitializePhase2();
|
||||
|
|
|
@ -79,6 +79,9 @@ namespace ams::kern::init {
|
|||
constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo));
|
||||
static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize);
|
||||
|
||||
static_assert(KernelPageBufferHeapSize == 2 * PageSize + (SlabCountKProcess + SlabCountKThread + (SlabCountKProcess + SlabCountKThread) / 8) * PageSize);
|
||||
static_assert(KernelPageBufferAdditionalSize == (SlabCountExtraKThread + (SlabCountExtraKThread / 8)) * PageSize);
|
||||
|
||||
}
|
||||
|
||||
/* Global to hold our resource counts. */
|
||||
|
@ -131,7 +134,7 @@ namespace ams::kern::init {
|
|||
}
|
||||
|
||||
size_t CalculateSlabHeapGapSize() {
|
||||
constexpr size_t KernelSlabHeapGapSize = 2_MB - 296_KB;
|
||||
constexpr size_t KernelSlabHeapGapSize = 2_MB - 320_KB;
|
||||
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
|
||||
return KernelSlabHeapGapSize;
|
||||
}
|
||||
|
@ -155,23 +158,6 @@ namespace ams::kern::init {
|
|||
return size;
|
||||
}
|
||||
|
||||
void InitializeKPageBufferSlabHeap() {
|
||||
const auto &counts = GetSlabResourceCounts();
|
||||
const size_t num_pages = counts.num_KProcess + counts.num_KThread + (counts.num_KProcess + counts.num_KThread) / 8;
|
||||
const size_t slab_size = num_pages * PageSize;
|
||||
|
||||
/* Reserve memory from the system resource limit. */
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, slab_size));
|
||||
|
||||
/* Allocate memory for the slab. */
|
||||
constexpr auto AllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
const KPhysicalAddress slab_address = Kernel::GetMemoryManager().AllocateAndOpenContinuous(num_pages, 1, AllocateOption);
|
||||
MESOSPHERE_ABORT_UNLESS(slab_address != Null<KPhysicalAddress>);
|
||||
|
||||
/* Initialize the slabheap. */
|
||||
KPageBuffer::InitializeSlabHeap(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(slab_address)), slab_size);
|
||||
}
|
||||
|
||||
void InitializeSlabHeaps() {
|
||||
/* Get the slab region, since that's where we'll be working. */
|
||||
const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion();
|
||||
|
@ -240,4 +226,34 @@ namespace ams::kern::init {
|
|||
FreeUnusedSlabMemory(gap_start, gap_size + (slab_region.GetEndAddress() - GetInteger(address)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
void KPageBufferSlabHeap::Initialize(KDynamicPageManager &allocator) {
|
||||
/* Get slab resource counts. */
|
||||
const auto &counts = init::GetSlabResourceCounts();
|
||||
|
||||
/* If size is correct, account for thread local pages. */
|
||||
if (BufferSize == PageSize) {
|
||||
s_buffer_count += counts.num_KProcess + counts.num_KThread + (counts.num_KProcess + counts.num_KThread) / 8;
|
||||
}
|
||||
|
||||
/* Set our object size. */
|
||||
m_obj_size = BufferSize;
|
||||
|
||||
/* Initialize the base allocator. */
|
||||
KSlabHeapImpl::Initialize();
|
||||
|
||||
/* Allocate the desired page count. */
|
||||
for (size_t i = 0; i < s_buffer_count; ++i) {
|
||||
/* Allocate an appropriate buffer. */
|
||||
auto * const pb = (BufferSize <= PageSize) ? allocator.Allocate() : allocator.Allocate(BufferSize / PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(pb != nullptr);
|
||||
|
||||
/* Free to our slab. */
|
||||
KSlabHeapImpl::Free(pb);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -332,7 +332,6 @@ namespace ams::kern::KDumpObject {
|
|||
MESOSPHERE_RELEASE_LOG(#__OBJECT__ "\n"); \
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%3zu Peak=%3zu Max=%3zu\n", __OBJECT__::GetSlabHeapSize() - __OBJECT__::GetNumRemaining(), __OBJECT__::GetPeakIndex(), __OBJECT__::GetSlabHeapSize())
|
||||
|
||||
DUMP_KSLABOBJ(KPageBuffer);
|
||||
DUMP_KSLABOBJ(KEvent);
|
||||
DUMP_KSLABOBJ(KInterruptEvent);
|
||||
DUMP_KSLABOBJ(KProcess);
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
size_t KMemoryLayout::GetResourceRegionSizeForInit(bool use_extra_resource) {
|
||||
return KernelResourceSize + (use_extra_resource ? KernelSlabHeapAdditionalSize : 0);
|
||||
return KernelResourceSize + KSystemControl::SecureAppletMemorySize + (use_extra_resource ? KernelSlabHeapAdditionalSize + KernelPageBufferAdditionalSize : 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ namespace ams::kern {
|
|||
return m_recv_list_count > ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsToMessageBuffer() const {
|
||||
return m_recv_list_count == ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer;
|
||||
}
|
||||
|
||||
void GetBuffer(uintptr_t &out, size_t size, int &key) const {
|
||||
switch (m_recv_list_count) {
|
||||
case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_None:
|
||||
|
@ -264,12 +268,12 @@ namespace ams::kern {
|
|||
static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite),
|
||||
KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_Locked,
|
||||
src_pointer,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_FlagLinearMapped, KMemoryState_FlagLinearMapped,
|
||||
KMemoryPermission_UserRead,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
} else {
|
||||
R_TRY(src_page_table.CopyMemoryFromLinearToUser(recv_pointer, recv_size, src_pointer,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_FlagLinearMapped, KMemoryState_FlagLinearMapped,
|
||||
KMemoryPermission_UserRead,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
}
|
||||
|
@ -642,12 +646,15 @@ namespace ams::kern {
|
|||
const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize);
|
||||
const size_t fast_size = max_fast_size - offset_words;
|
||||
|
||||
/* Determine source state; if user buffer, we require heap, and otherwise only linear mapped (to enable tls use). */
|
||||
const auto src_state = src_user ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped;
|
||||
|
||||
/* Determine the source permission. User buffer should be unmapped + read, TLS should be user readable. */
|
||||
const KMemoryPermission src_perm = static_cast<KMemoryPermission>(src_user ? KMemoryPermission_NotMapped | KMemoryPermission_KernelRead : KMemoryPermission_UserRead);
|
||||
|
||||
/* Perform the fast part of the copy. */
|
||||
R_TRY(src_page_table.CopyMemoryFromLinearToKernel(reinterpret_cast<uintptr_t>(dst_msg_ptr) + offset_words, fast_size, src_message_buffer + offset_words,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
src_state, src_state,
|
||||
src_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
|
||||
|
@ -658,7 +665,7 @@ namespace ams::kern {
|
|||
static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite),
|
||||
KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_Locked,
|
||||
src_message_buffer + max_fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
src_state, src_state,
|
||||
src_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
}
|
||||
|
@ -744,9 +751,11 @@ namespace ams::kern {
|
|||
R_UNLESS(recv_pointer != 0, svc::ResultOutOfResource());
|
||||
|
||||
/* Perform the pointer data copy. */
|
||||
const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_user ? KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite : KMemoryPermission_UserReadWrite);
|
||||
const bool dst_heap = dst_user && dst_recv_list.IsToMessageBuffer();
|
||||
const auto dst_state = dst_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped;
|
||||
const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_heap ? KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite : KMemoryPermission_UserReadWrite);
|
||||
R_TRY(dst_page_table.CopyMemoryFromUserToLinear(recv_pointer, recv_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
dst_state, dst_state,
|
||||
dst_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None,
|
||||
src_pointer));
|
||||
|
@ -898,12 +907,15 @@ namespace ams::kern {
|
|||
const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize);
|
||||
const size_t fast_size = max_fast_size - offset_words;
|
||||
|
||||
/* Determine dst state; if user buffer, we require heap, and otherwise only linear mapped (to enable tls use). */
|
||||
const auto dst_state = dst_user ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped;
|
||||
|
||||
/* Determine the dst permission. User buffer should be unmapped + read, TLS should be user readable. */
|
||||
const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_user ? KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite : KMemoryPermission_UserReadWrite);
|
||||
|
||||
/* Perform the fast part of the copy. */
|
||||
R_TRY(dst_page_table.CopyMemoryFromKernelToLinear(dst_message_buffer + offset_words, fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
dst_state, dst_state,
|
||||
dst_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None,
|
||||
reinterpret_cast<uintptr_t>(src_msg_ptr) + offset_words));
|
||||
|
@ -911,7 +923,7 @@ namespace ams::kern {
|
|||
/* If the fast part of the copy didn't get everything, perform the slow part of the copy. */
|
||||
if (fast_size < raw_size) {
|
||||
R_TRY(dst_page_table.CopyMemoryFromHeapToHeap(dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
dst_state, dst_state,
|
||||
dst_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None,
|
||||
src_message_buffer + max_fast_size,
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace ams::kern {
|
|||
R_UNLESS(m_resource_size > rc_size, svc::ResultOutOfMemory());
|
||||
|
||||
/* Initialize slab heaps. */
|
||||
m_dynamic_page_manager.Initialize(m_resource_address + rc_size, m_resource_size - rc_size);
|
||||
m_dynamic_page_manager.Initialize(m_resource_address + rc_size, m_resource_size - rc_size, PageSize);
|
||||
m_page_table_heap.Initialize(std::addressof(m_dynamic_page_manager), 0, GetPointer<KPageTableManager::RefCount>(m_resource_address));
|
||||
m_memory_block_heap.Initialize(std::addressof(m_dynamic_page_manager), 0);
|
||||
m_block_info_heap.Initialize(std::addressof(m_dynamic_page_manager), 0);
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace ams::kern {
|
|||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPages(stack_bottom, 1, KMemoryState_Kernel));
|
||||
|
||||
/* Free the stack page. */
|
||||
KPageBuffer::Free(KPageBuffer::FromPhysicalAddress(stack_paddr));
|
||||
KPageBuffer::FreeChecked<PageSize>(KPageBuffer::FromPhysicalAddress(stack_paddr));
|
||||
}
|
||||
|
||||
class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { /* ... */ };
|
||||
|
@ -334,7 +334,7 @@ namespace ams::kern {
|
|||
MESOSPHERE_ABORT_UNLESS(stack_region.GetEndAddress() != 0);
|
||||
|
||||
/* Allocate a page to use as the thread. */
|
||||
KPageBuffer *page = KPageBuffer::Allocate();
|
||||
KPageBuffer *page = KPageBuffer::AllocateChecked<PageSize>();
|
||||
R_UNLESS(page != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
/* Map the stack page. */
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace ams::kern {
|
|||
m_owner = process;
|
||||
|
||||
/* Allocate a new page. */
|
||||
KPageBuffer *page_buf = KPageBuffer::Allocate();
|
||||
KPageBuffer *page_buf = KPageBuffer::AllocateChecked<PageSize>();
|
||||
R_UNLESS(page_buf != nullptr, svc::ResultOutOfMemory());
|
||||
ON_RESULT_FAILURE { KPageBuffer::Free(page_buf); };
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace ams::kern {
|
|||
R_TRY(m_owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState_ThreadLocal));
|
||||
|
||||
/* Free the page. */
|
||||
KPageBuffer::Free(KPageBuffer::FromPhysicalAddress(phys_addr));
|
||||
KPageBuffer::FreeChecked<PageSize>(KPageBuffer::FromPhysicalAddress(phys_addr));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,10 @@ namespace ams::kern {
|
|||
size -= rc_size;
|
||||
|
||||
/* Initialize the resource managers' shared page manager. */
|
||||
g_resource_manager_page_manager.Initialize(address, size);
|
||||
g_resource_manager_page_manager.Initialize(address, size, std::max<size_t>(PageSize, KPageBufferSlabHeap::BufferSize));
|
||||
|
||||
/* Initialize the KPageBuffer slab heap. */
|
||||
KPageBuffer::InitializeSlabHeap(g_resource_manager_page_manager);
|
||||
|
||||
/* Initialize the fixed-size slabheaps. */
|
||||
s_app_memory_block_heap.Initialize(std::addressof(g_resource_manager_page_manager), ApplicationMemoryBlockSlabHeapSize);
|
||||
|
@ -143,6 +146,9 @@ namespace ams::kern {
|
|||
PrintMemoryRegion(" KernelRegion", KMemoryLayout::GetKernelRegionPhysicalExtents());
|
||||
PrintMemoryRegion(" Code", KMemoryLayout::GetKernelCodeRegionPhysicalExtents());
|
||||
PrintMemoryRegion(" Slab", KMemoryLayout::GetKernelSlabRegionPhysicalExtents());
|
||||
if constexpr (KSystemControl::SecureAppletMemorySize > 0) {
|
||||
PrintMemoryRegion(" SecureApplet", KMemoryLayout::GetKernelSecureAppletMemoryRegionPhysicalExtents());
|
||||
}
|
||||
PrintMemoryRegion(" PageTableHeap", KMemoryLayout::GetKernelPageTableHeapRegionPhysicalExtents());
|
||||
PrintMemoryRegion(" InitPageTable", KMemoryLayout::GetKernelInitPageTableRegionPhysicalExtents());
|
||||
if constexpr (IsKTraceEnabled) {
|
||||
|
|
|
@ -58,7 +58,6 @@ namespace ams::kern {
|
|||
MESOSPHERE_ABORT_UNLESS(management_region.GetEndAddress() != 0);
|
||||
|
||||
Kernel::GetMemoryManager().Initialize(management_region.GetAddress(), management_region.GetSize());
|
||||
init::InitializeKPageBufferSlabHeap();
|
||||
}
|
||||
|
||||
/* Copy the Initial Process Binary to safe memory. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue