mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
kern: Implement SecureMemory (system resource)
This commit is contained in:
parent
9231646f33
commit
fd9b986938
3 changed files with 189 additions and 20 deletions
|
@ -154,13 +154,11 @@ namespace ams::kern {
|
|||
constexpr KProcessAddress GetEntryPoint() const { return this->code_address; }
|
||||
|
||||
constexpr u64 GetRandomEntropy(size_t i) const { return this->entropy[i]; }
|
||||
constexpr bool IsSuspended() const {
|
||||
return this->is_suspended;
|
||||
}
|
||||
|
||||
constexpr void SetSuspended(bool suspended) {
|
||||
this->is_suspended = suspended;
|
||||
}
|
||||
constexpr bool IsApplication() const { return this->is_application; }
|
||||
|
||||
constexpr bool IsSuspended() const { return this->is_suspended; }
|
||||
constexpr void SetSuspended(bool suspended) { this->is_suspended = suspended; }
|
||||
|
||||
Result Terminate();
|
||||
|
||||
|
@ -246,6 +244,14 @@ namespace ams::kern {
|
|||
void IncrementThreadCount();
|
||||
void DecrementThreadCount();
|
||||
|
||||
size_t GetTotalSystemResourceSize() const { return this->system_resource_num_pages * PageSize; }
|
||||
size_t GetUsedSystemResourceSize() const {
|
||||
if (this->system_resource_num_pages == 0) {
|
||||
return 0;
|
||||
}
|
||||
return this->dynamic_page_manager.GetUsed() * PageSize;
|
||||
}
|
||||
|
||||
void ClearRunningThread(KThread *thread) {
|
||||
for (size_t i = 0; i < util::size(this->running_threads); ++i) {
|
||||
if (this->running_threads[i] == thread) {
|
||||
|
|
|
@ -21,13 +21,21 @@ namespace ams::kern::board::nintendo::nx {
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr size_t SecureAlignment = 128_KB;
|
||||
|
||||
/* Global variables for panic. */
|
||||
bool g_call_smc_on_panic;
|
||||
constinit bool g_call_smc_on_panic;
|
||||
|
||||
/* Global variables for secure memory. */
|
||||
constexpr size_t SecureAppletReservedMemorySize = 4_MB;
|
||||
KVirtualAddress g_secure_applet_memory_address;
|
||||
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>;
|
||||
|
||||
constinit KSpinLock g_secure_region_lock;
|
||||
constinit bool g_secure_region_used = false;
|
||||
constinit KPhysicalAddress g_secure_region_phys_addr = Null<KPhysicalAddress>;
|
||||
constinit size_t g_secure_region_size = 0;
|
||||
|
||||
/* Global variables for randomness. */
|
||||
/* Nintendo uses std::mt19937_t for randomness. */
|
||||
|
@ -35,7 +43,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
/* We will use TinyMT. */
|
||||
bool g_initialized_random_generator;
|
||||
util::TinyMT g_random_generator;
|
||||
KSpinLock g_random_lock;
|
||||
constinit KSpinLock g_random_lock;
|
||||
|
||||
ALWAYS_INLINE size_t GetRealMemorySizeForInit() {
|
||||
/* TODO: Move this into a header for the MC in general. */
|
||||
|
@ -216,6 +224,90 @@ namespace ams::kern::board::nintendo::nx {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SetSecureRegion(KPhysicalAddress phys_addr, size_t size) {
|
||||
/* Ensure address and size are aligned. */
|
||||
if (!util::IsAligned(GetInteger(phys_addr), SecureAlignment)) {
|
||||
return false;
|
||||
}
|
||||
if (!util::IsAligned(size, SecureAlignment)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Disable interrupts and acquire the secure region lock. */
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(g_secure_region_lock);
|
||||
|
||||
/* If size is non-zero, we're allocating the secure region. Otherwise, we're freeing it. */
|
||||
if (size != 0) {
|
||||
/* Verify that the secure region is free. */
|
||||
if (g_secure_region_used) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the secure region. */
|
||||
g_secure_region_used = true;
|
||||
g_secure_region_phys_addr = phys_addr;
|
||||
g_secure_region_size = size;
|
||||
} else {
|
||||
/* Verify that the secure region is in use. */
|
||||
if (!g_secure_region_used) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Verify that the address being freed is the secure region. */
|
||||
if (phys_addr != g_secure_region_phys_addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Clear the secure region. */
|
||||
g_secure_region_used = false;
|
||||
g_secure_region_phys_addr = Null<KPhysicalAddress>;
|
||||
g_secure_region_size = 0;
|
||||
}
|
||||
|
||||
/* Configure the carveout with the secure monitor. */
|
||||
smc::ConfigureCarveout(1, GetInteger(phys_addr), size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
/* Disable interrupts and acquire the secure applet lock. */
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(g_secure_applet_lock);
|
||||
|
||||
/* Check that memory is reserved for secure applet use. */
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>);
|
||||
|
||||
/* Verify that the secure applet memory isn't already being used. */
|
||||
R_UNLESS(!g_secure_applet_memory_used, svc::ResultOutOfMemory());
|
||||
|
||||
/* Return the secure applet memory. */
|
||||
g_secure_applet_memory_used = true;
|
||||
*out = g_secure_applet_memory_address;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void FreeSecureMemoryForApplet(KVirtualAddress address, size_t size) {
|
||||
/* Disable interrupts and acquire the secure applet lock. */
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(g_secure_applet_lock);
|
||||
|
||||
/* 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(util::IsAligned(size, PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_used);
|
||||
|
||||
/* Release the secure applet memory. */
|
||||
g_secure_applet_memory_used = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Initialization. */
|
||||
|
@ -363,10 +455,10 @@ namespace ams::kern::board::nintendo::nx {
|
|||
/* Reserve secure applet memory. */
|
||||
{
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null<KVirtualAddress>);
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletReservedMemorySize));
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletMemorySize));
|
||||
|
||||
constexpr auto SecureAppletAllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
g_secure_applet_memory_address = Kernel::GetMemoryManager().AllocateContinuous(SecureAppletReservedMemorySize / PageSize, 1, SecureAppletAllocateOption);
|
||||
g_secure_applet_memory_address = Kernel::GetMemoryManager().AllocateContinuous(SecureAppletMemorySize / PageSize, 1, SecureAppletAllocateOption);
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>);
|
||||
}
|
||||
}
|
||||
|
@ -480,11 +572,71 @@ namespace ams::kern::board::nintendo::nx {
|
|||
}
|
||||
|
||||
Result KSystemControl::AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool) {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
/* Applet secure memory is handled separately. */
|
||||
if (pool == KMemoryManager::Pool_Applet) {
|
||||
return AllocateSecureMemoryForApplet(out, size);
|
||||
}
|
||||
|
||||
/* Ensure the size is aligned. */
|
||||
const size_t alignment = (pool == KMemoryManager::Pool_System ? PageSize : SecureAlignment);
|
||||
R_UNLESS(util::IsAligned(size, alignment), svc::ResultInvalidSize());
|
||||
|
||||
/* Allocate the memory. */
|
||||
const size_t num_pages = size / PageSize;
|
||||
const KVirtualAddress vaddr = Kernel::GetMemoryManager().AllocateContinuous(num_pages, alignment / PageSize, KMemoryManager::EncodeOption(static_cast<KMemoryManager::Pool>(pool), KMemoryManager::Direction_FromFront));
|
||||
R_UNLESS(vaddr != Null<KVirtualAddress>, svc::ResultOutOfMemory());
|
||||
|
||||
/* Open a reference to the memory. */
|
||||
Kernel::GetMemoryManager().Open(vaddr, num_pages);
|
||||
|
||||
/* Ensure we don't leak references to the memory on error. */
|
||||
auto mem_guard = SCOPE_GUARD { Kernel::GetMemoryManager().Close(vaddr, num_pages); };
|
||||
|
||||
/* If the memory isn't already secure, set it as secure. */
|
||||
if (pool != KMemoryManager::Pool_System) {
|
||||
/* Get the physical address. */
|
||||
const KPhysicalAddress paddr = KPageTable::GetHeapPhysicalAddress(vaddr);
|
||||
MESOSPHERE_ABORT_UNLESS(paddr != Null<KPhysicalAddress>);
|
||||
|
||||
/* Set the secure region. */
|
||||
R_UNLESS(SetSecureRegion(paddr, size), svc::ResultOutOfMemory());
|
||||
}
|
||||
|
||||
/* We succeeded. */
|
||||
mem_guard.Cancel();
|
||||
*out = vaddr;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void KSystemControl::FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool) {
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
/* Applet secure memory is handled separately. */
|
||||
if (pool == KMemoryManager::Pool_Applet) {
|
||||
return FreeSecureMemoryForApplet(address, size);
|
||||
}
|
||||
|
||||
/* Ensure the size is aligned. */
|
||||
const size_t alignment = (pool == KMemoryManager::Pool_System ? PageSize : SecureAlignment);
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(address), alignment));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, alignment));
|
||||
|
||||
/* If the memory isn't secure system, reset the secure region. */
|
||||
if (pool != KMemoryManager::Pool_System) {
|
||||
/* Check that the size being freed is the current secure region size. */
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_region_size == size);
|
||||
|
||||
/* Get the physical address. */
|
||||
const KPhysicalAddress paddr = KPageTable::GetHeapPhysicalAddress(address);
|
||||
MESOSPHERE_ABORT_UNLESS(paddr != Null<KPhysicalAddress>);
|
||||
|
||||
/* Check that the memory being freed is the current secure region. */
|
||||
MESOSPHERE_ABORT_UNLESS(paddr == g_secure_region_phys_addr);
|
||||
|
||||
/* Free the secure region. */
|
||||
MESOSPHERE_ABORT_UNLESS(SetSecureRegion(paddr, 0));
|
||||
}
|
||||
|
||||
/* Close the secure region's pages. */
|
||||
Kernel::GetMemoryManager().Close(address, size / PageSize);
|
||||
}
|
||||
|
||||
}
|
|
@ -22,9 +22,6 @@ namespace ams::kern::svc {
|
|||
namespace {
|
||||
|
||||
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
||||
MESOSPHERE_LOG("GetInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
|
||||
ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetInfo returned %016lx\n", *out); };
|
||||
|
||||
switch (info_type) {
|
||||
case ams::svc::InfoType_CoreMask:
|
||||
case ams::svc::InfoType_PriorityMask:
|
||||
|
@ -38,11 +35,14 @@ namespace ams::kern::svc {
|
|||
case ams::svc::InfoType_AslrRegionSize:
|
||||
case ams::svc::InfoType_StackRegionAddress:
|
||||
case ams::svc::InfoType_StackRegionSize:
|
||||
case ams::svc::InfoType_SystemResourceSizeTotal:
|
||||
case ams::svc::InfoType_SystemResourceSizeUsed:
|
||||
case ams::svc::InfoType_ProgramId:
|
||||
case ams::svc::InfoType_InitialProcessIdRange:
|
||||
case ams::svc::InfoType_UserExceptionContextAddress:
|
||||
case ams::svc::InfoType_TotalNonSystemMemorySize:
|
||||
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
||||
case ams::svc::InfoType_IsApplication:
|
||||
{
|
||||
/* These info types don't support non-zero subtypes. */
|
||||
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
||||
|
@ -88,6 +88,12 @@ namespace ams::kern::svc {
|
|||
case ams::svc::InfoType_StackRegionSize:
|
||||
*out = process->GetPageTable().GetStackRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_SystemResourceSizeTotal:
|
||||
*out = process->GetTotalSystemResourceSize();
|
||||
break;
|
||||
case ams::svc::InfoType_SystemResourceSizeUsed:
|
||||
*out = process->GetUsedSystemResourceSize();
|
||||
break;
|
||||
case ams::svc::InfoType_ProgramId:
|
||||
*out = process->GetProgramId();
|
||||
break;
|
||||
|
@ -103,6 +109,9 @@ namespace ams::kern::svc {
|
|||
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
||||
*out = process->GetUsedNonSystemUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_IsApplication:
|
||||
*out = process->IsApplication();
|
||||
break;
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +166,11 @@ namespace ams::kern::svc {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
/* For debug, until all infos are implemented. */
|
||||
MESOSPHERE_LOG("GetInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
|
||||
MESOSPHERE_UNIMPLEMENTED();
|
||||
}
|
||||
return svc::ResultInvalidEnumValue();
|
||||
}
|
||||
|
||||
|
@ -176,9 +190,6 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result GetSystemInfo(u64 *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
||||
MESOSPHERE_LOG("GetSystemInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
|
||||
ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetSystemInfo returned %016lx\n", *out); };
|
||||
|
||||
switch (info_type) {
|
||||
case ams::svc::SystemInfoType_TotalPhysicalMemorySize:
|
||||
case ams::svc::SystemInfoType_UsedPhysicalMemorySize:
|
||||
|
|
Loading…
Reference in a new issue