Compare commits
12 Commits
gcc-12-sup
...
revision
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
070d2786c6 | ||
|
|
efa4a346af | ||
|
|
d75f9bbedf | ||
|
|
ea7f51a279 | ||
|
|
a65b6df8d2 | ||
|
|
4e112de223 | ||
|
|
20d200471d | ||
|
|
5f2d713fe4 | ||
|
|
114d2598da | ||
|
|
36bdb83cfc | ||
|
|
a975689c59 | ||
|
|
a809e23320 |
@@ -123,7 +123,7 @@ namespace ams::kern {
|
||||
s32 new_value;
|
||||
if (count <= 0) {
|
||||
if ((it != m_tree.end()) && (it->GetAddressArbiterKey() == addr)) {
|
||||
new_value = value - 2;
|
||||
new_value = value - 1;
|
||||
} else {
|
||||
new_value = value + 1;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ namespace ams::kern {
|
||||
auto tmp_it = it;
|
||||
s32 tmp_num_waiters = 0;
|
||||
while ((++tmp_it != m_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr)) {
|
||||
if ((tmp_num_waiters++) >= count) {
|
||||
if ((++tmp_num_waiters) >= count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,8 @@ namespace ams::fssystem {
|
||||
AMS_UNUSED(size);
|
||||
R_THROW(fs::ResultUnsupportedSetSizeForAesCtrCounterExtendedStorage());
|
||||
}
|
||||
|
||||
Result GetEntryList(Entry *out_entries, s32 *out_entry_count, s32 entry_count, s64 offset, s64 size);
|
||||
private:
|
||||
Result Initialize(IAllocator *allocator, const void *key, size_t key_size, u32 secure_value, fs::SubStorage data_storage, fs::SubStorage table_storage);
|
||||
};
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
#include <stratosphere/os/os_memory_common.hpp>
|
||||
#include <stratosphere/os/os_memory_fence.hpp>
|
||||
#include <stratosphere/os/os_memory_permission.hpp>
|
||||
#include <stratosphere/os/os_memory_heap_api.hpp>
|
||||
#include <stratosphere/os/os_memory_attribute.hpp>
|
||||
#include <stratosphere/os/os_memory_heap.hpp>
|
||||
#include <stratosphere/os/os_virtual_address_memory.hpp>
|
||||
#include <stratosphere/os/os_native_handle.hpp>
|
||||
#include <stratosphere/os/os_process_handle_api.hpp>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_common_types.hpp>
|
||||
#include <stratosphere/os/os_memory_common.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
enum MemoryAttribute {
|
||||
MemoryAttribute_Normal,
|
||||
MemoryAttribute_Uncached,
|
||||
};
|
||||
|
||||
void SetMemoryAttribute(uintptr_t address, size_t size, MemoryAttribute attr);
|
||||
|
||||
}
|
||||
@@ -18,10 +18,6 @@
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
constexpr inline size_t MemoryPageSize = 0x1000;
|
||||
|
||||
constexpr inline size_t MemoryBlockUnitSize = 0x200000;
|
||||
|
||||
enum MemoryPermission {
|
||||
MemoryPermission_None = (0 << 0),
|
||||
MemoryPermission_ReadOnly = (1 << 0),
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_memory_heap_common.hpp>
|
||||
#include <stratosphere/os/os_memory_heap_api.hpp>
|
||||
@@ -16,10 +16,15 @@
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_common_types.hpp>
|
||||
#include <stratosphere/os/os_memory_common.hpp>
|
||||
#include <stratosphere/os/os_memory_heap_common.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
Result SetMemoryHeapSize(size_t size);
|
||||
|
||||
uintptr_t GetMemoryHeapAddress();
|
||||
size_t GetMemoryHeapSize();
|
||||
|
||||
Result AllocateMemoryBlock(uintptr_t *out_address, size_t size);
|
||||
void FreeMemoryBlock(uintptr_t address, size_t size);
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_common_types.hpp>
|
||||
#include <stratosphere/os/os_memory_common.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
constexpr inline size_t MemoryHeapUnitSize = 2_MB;
|
||||
constexpr inline size_t MemoryBlockUnitSize = 2_MB;
|
||||
|
||||
constexpr inline size_t MemoryPageSize = 4_KB;
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
|
||||
namespace ams::svc {
|
||||
|
||||
@@ -22,485 +22,10 @@
|
||||
|
||||
namespace aarch64::lp64 {
|
||||
|
||||
ALWAYS_INLINE Result SetHeapSize(::ams::svc::Address *out_address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcSetHeapSize(reinterpret_cast<void **>(out_address), size));
|
||||
}
|
||||
|
||||
/* Convenience accessor. */
|
||||
ALWAYS_INLINE Result SetHeapSize(uintptr_t *out_address, ::ams::svc::Size size) {
|
||||
static_assert(sizeof(::ams::svc::Address) == sizeof(uintptr_t));
|
||||
R_RETURN(::svcSetHeapSize(reinterpret_cast<void **>(out_address), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetMemoryPermission(::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission perm) {
|
||||
R_RETURN(::svcSetMemoryPermission(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetMemoryAttribute(::ams::svc::Address address, ::ams::svc::Size size, uint32_t mask, uint32_t attr) {
|
||||
R_RETURN(::svcSetMemoryAttribute(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, mask, attr));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapMemory(::ams::svc::Address dst_address, ::ams::svc::Address src_address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcMapMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), reinterpret_cast<void *>(static_cast<uintptr_t>(src_address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapMemory(::ams::svc::Address dst_address, ::ams::svc::Address src_address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcUnmapMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), reinterpret_cast<void *>(static_cast<uintptr_t>(src_address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result QueryMemory(::ams::svc::UserPointer< ::ams::svc::lp64::MemoryInfo *> out_memory_info, ::ams::svc::PageInfo *out_page_info, ::ams::svc::Address address) {
|
||||
R_RETURN(::svcQueryMemory(reinterpret_cast<::MemoryInfo *>(out_memory_info.GetPointerUnsafe()), reinterpret_cast<u32 *>(out_page_info), address));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void ExitProcess() {
|
||||
return ::svcExitProcess();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateThread(::ams::svc::Handle *out_handle, ::ams::svc::ThreadFunc func, ::ams::svc::Address arg, ::ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) {
|
||||
R_RETURN(::svcCreateThread(out_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(func)), reinterpret_cast<void *>(static_cast<uintptr_t>(arg)), reinterpret_cast<void *>(static_cast<uintptr_t>(stack_bottom)), priority, core_id));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result StartThread(::ams::svc::Handle thread_handle) {
|
||||
R_RETURN(::svcStartThread(thread_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void ExitThread() {
|
||||
return ::svcExitThread();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SleepThread(int64_t ns) {
|
||||
return ::svcSleepThread(ns);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetThreadPriority(int32_t *out_priority, ::ams::svc::Handle thread_handle) {
|
||||
R_RETURN(::svcGetThreadPriority(out_priority, thread_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetThreadPriority(::ams::svc::Handle thread_handle, int32_t priority) {
|
||||
R_RETURN(::svcSetThreadPriority(thread_handle, priority));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetThreadCoreMask(int32_t *out_core_id, uint64_t *out_affinity_mask, ::ams::svc::Handle thread_handle) {
|
||||
R_RETURN(::svcGetThreadCoreMask(out_core_id, out_affinity_mask, thread_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetThreadCoreMask(::ams::svc::Handle thread_handle, int32_t core_id, uint64_t affinity_mask) {
|
||||
R_RETURN(::svcSetThreadCoreMask(thread_handle, core_id, affinity_mask));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int32_t GetCurrentProcessorNumber() {
|
||||
return ::svcGetCurrentProcessorNumber();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SignalEvent(::ams::svc::Handle event_handle) {
|
||||
R_RETURN(::svcSignalEvent(event_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ClearEvent(::ams::svc::Handle event_handle) {
|
||||
R_RETURN(::svcClearEvent(event_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapSharedMemory(::ams::svc::Handle shmem_handle, ::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission map_perm) {
|
||||
R_RETURN(::svcMapSharedMemory(shmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(map_perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapSharedMemory(::ams::svc::Handle shmem_handle, ::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcUnmapSharedMemory(shmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateTransferMemory(::ams::svc::Handle *out_handle, ::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission map_perm) {
|
||||
R_RETURN(::svcCreateTransferMemory(out_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(map_perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CloseHandle(::ams::svc::Handle handle) {
|
||||
R_RETURN(::svcCloseHandle(handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ResetSignal(::ams::svc::Handle handle) {
|
||||
R_RETURN(::svcResetSignal(handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result WaitSynchronization(int32_t *out_index, ::ams::svc::UserPointer<const ::ams::svc::Handle *> handles, int32_t num_handles, int64_t timeout_ns) {
|
||||
R_RETURN(::svcWaitSynchronization(out_index, handles.GetPointerUnsafe(), num_handles, timeout_ns));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CancelSynchronization(::ams::svc::Handle handle) {
|
||||
R_RETURN(::svcCancelSynchronization(handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ArbitrateLock(::ams::svc::Handle thread_handle, ::ams::svc::Address address, uint32_t tag) {
|
||||
R_RETURN(::svcArbitrateLock(thread_handle, reinterpret_cast<u32 *>(static_cast<uintptr_t>(address)), tag));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ArbitrateUnlock(::ams::svc::Address address) {
|
||||
R_RETURN(::svcArbitrateUnlock(reinterpret_cast<u32 *>(static_cast<uintptr_t>(address))));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result WaitProcessWideKeyAtomic(::ams::svc::Address address, ::ams::svc::Address cv_key, uint32_t tag, int64_t timeout_ns) {
|
||||
R_RETURN(::svcWaitProcessWideKeyAtomic(reinterpret_cast<u32 *>(static_cast<uintptr_t>(address)), reinterpret_cast<u32 *>(static_cast<uintptr_t>(cv_key)), tag, timeout_ns));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SignalProcessWideKey(::ams::svc::Address cv_key, int32_t count) {
|
||||
return ::svcSignalProcessWideKey(reinterpret_cast<u32 *>(static_cast<uintptr_t>(cv_key)), count);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int64_t GetSystemTick() {
|
||||
return ::svcGetSystemTick();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ConnectToNamedPort(::ams::svc::Handle *out_handle, ::ams::svc::UserPointer<const char *> name) {
|
||||
R_RETURN(::svcConnectToNamedPort(out_handle, name.GetPointerUnsafe()));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SendSyncRequestLight(::ams::svc::Handle session_handle) {
|
||||
R_RETURN(::svcSendSyncRequestLight(session_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SendSyncRequest(::ams::svc::Handle session_handle) {
|
||||
R_RETURN(::svcSendSyncRequest(session_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SendSyncRequestWithUserBuffer(::ams::svc::Address message_buffer, ::ams::svc::Size message_buffer_size, ::ams::svc::Handle session_handle) {
|
||||
R_RETURN(::svcSendSyncRequestWithUserBuffer(reinterpret_cast<void *>(static_cast<uintptr_t>(message_buffer)), message_buffer_size, session_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SendAsyncRequestWithUserBuffer(::ams::svc::Handle *out_event_handle, ::ams::svc::Address message_buffer, ::ams::svc::Size message_buffer_size, ::ams::svc::Handle session_handle) {
|
||||
R_RETURN(::svcSendAsyncRequestWithUserBuffer(out_event_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(message_buffer)), message_buffer_size, session_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetProcessId(uint64_t *out_process_id, ::ams::svc::Handle process_handle) {
|
||||
R_RETURN(::svcGetProcessId(out_process_id, process_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetThreadId(uint64_t *out_thread_id, ::ams::svc::Handle thread_handle) {
|
||||
R_RETURN(::svcGetThreadId(out_thread_id, thread_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Break(::ams::svc::BreakReason break_reason, ::ams::svc::Address arg, ::ams::svc::Size size) {
|
||||
::svcBreak(break_reason, arg, size);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result OutputDebugString(::ams::svc::UserPointer<const char *> debug_str, ::ams::svc::Size len) {
|
||||
R_RETURN(::svcOutputDebugString(debug_str.GetPointerUnsafe(), len));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void ReturnFromException(::ams::Result result) {
|
||||
return ::svcReturnFromException(result.GetValue());
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetInfo(uint64_t *out, ::ams::svc::InfoType info_type, ::ams::svc::Handle handle, uint64_t info_subtype) {
|
||||
R_RETURN(::svcGetInfo(out, static_cast<u32>(info_type), handle, info_subtype));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void FlushEntireDataCache() {
|
||||
return ::svcFlushEntireDataCache();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result FlushDataCache(::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcFlushDataCache(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapPhysicalMemory(::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcMapPhysicalMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapPhysicalMemory(::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcUnmapPhysicalMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetDebugFutureThreadInfo(::ams::svc::lp64::LastThreadContext *out_context, uint64_t *thread_id, ::ams::svc::Handle debug_handle, int64_t ns) {
|
||||
R_RETURN(::svcGetDebugFutureThreadInfo(reinterpret_cast<::LastThreadContext *>(out_context), thread_id, debug_handle, ns));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetLastThreadInfo(::ams::svc::lp64::LastThreadContext *out_context, ::ams::svc::Address *out_tls_address, uint32_t *out_flags) {
|
||||
R_RETURN(::svcGetLastThreadInfo(reinterpret_cast<::LastThreadContext *>(out_context), reinterpret_cast<u64 *>(out_tls_address), out_flags));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetResourceLimitLimitValue(int64_t *out_limit_value, ::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which) {
|
||||
R_RETURN(::svcGetResourceLimitLimitValue(out_limit_value, resource_limit_handle, static_cast<::LimitableResource>(which)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetResourceLimitCurrentValue(int64_t *out_current_value, ::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which) {
|
||||
R_RETURN(::svcGetResourceLimitCurrentValue(out_current_value, resource_limit_handle, static_cast<::LimitableResource>(which)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetThreadActivity(::ams::svc::Handle thread_handle, ::ams::svc::ThreadActivity thread_activity) {
|
||||
R_RETURN(::svcSetThreadActivity(thread_handle, static_cast<::ThreadActivity>(thread_activity)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetThreadContext3(::ams::svc::UserPointer< ::ams::svc::ThreadContext *> out_context, ::ams::svc::Handle thread_handle) {
|
||||
R_RETURN(::svcGetThreadContext3(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), thread_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
||||
R_RETURN(::svcWaitForAddress(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), arb_type, value, timeout_ns));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SignalToAddress(::ams::svc::Address address, ::ams::svc::SignalType signal_type, int32_t value, int32_t count) {
|
||||
R_RETURN(::svcSignalToAddress(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), signal_type, value, count));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SynchronizePreemptionState() {
|
||||
return ::svcSynchronizePreemptionState();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetResourceLimitPeakValue(int64_t *out_peak_value, ::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which) {
|
||||
R_RETURN(::svcGetResourceLimitPeakValue(out_peak_value, resource_limit_handle, static_cast<::LimitableResource>(which)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void KernelDebug(::ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) {
|
||||
return ::svcKernelDebug(kern_debug_type, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void ChangeKernelTraceState(::ams::svc::KernelTraceState kern_trace_state) {
|
||||
return ::svcChangeKernelTraceState(kern_trace_state);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateSession(::ams::svc::Handle *out_server_session_handle, ::ams::svc::Handle *out_client_session_handle, bool is_light, ::ams::svc::Address name) {
|
||||
R_RETURN(::svcCreateSession(out_server_session_handle, out_client_session_handle, is_light, name));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result AcceptSession(::ams::svc::Handle *out_handle, ::ams::svc::Handle port) {
|
||||
R_RETURN(::svcAcceptSession(out_handle, port));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ReplyAndReceiveLight(::ams::svc::Handle handle) {
|
||||
R_RETURN(::svcReplyAndReceiveLight(handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ReplyAndReceive(int32_t *out_index, ::ams::svc::UserPointer<const ::ams::svc::Handle *> handles, int32_t num_handles, ::ams::svc::Handle reply_target, int64_t timeout_ns) {
|
||||
R_RETURN(::svcReplyAndReceive(out_index, handles.GetPointerUnsafe(), num_handles, reply_target, timeout_ns));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ReplyAndReceiveWithUserBuffer(int32_t *out_index, ::ams::svc::Address message_buffer, ::ams::svc::Size message_buffer_size, ::ams::svc::UserPointer<const ::ams::svc::Handle *> handles, int32_t num_handles, ::ams::svc::Handle reply_target, int64_t timeout_ns) {
|
||||
R_RETURN(::svcReplyAndReceiveWithUserBuffer(out_index, reinterpret_cast<void *>(static_cast<uintptr_t>(message_buffer)), message_buffer_size, handles.GetPointerUnsafe(), num_handles, reply_target, timeout_ns));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateEvent(::ams::svc::Handle *out_write_handle, ::ams::svc::Handle *out_read_handle) {
|
||||
R_RETURN(::svcCreateEvent(out_write_handle, out_read_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapPhysicalMemoryUnsafe(::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcMapPhysicalMemoryUnsafe(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapPhysicalMemoryUnsafe(::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcUnmapPhysicalMemoryUnsafe(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetUnsafeLimit(::ams::svc::Size limit) {
|
||||
R_RETURN(::svcSetUnsafeLimit(limit));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateCodeMemory(::ams::svc::Handle *out_handle, ::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcCreateCodeMemory(out_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ControlCodeMemory(::ams::svc::Handle code_memory_handle, ::ams::svc::CodeMemoryOperation operation, uint64_t address, uint64_t size, ::ams::svc::MemoryPermission perm) {
|
||||
R_RETURN(::svcControlCodeMemory(code_memory_handle, static_cast<::CodeMapOperation>(operation), reinterpret_cast<void *>(address), size, static_cast<u32>(perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SleepSystem() {
|
||||
return ::svcSleepSystem();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ReadWriteRegister(uint32_t *out_value, ::ams::svc::PhysicalAddress address, uint32_t mask, uint32_t value) {
|
||||
R_RETURN(::svcReadWriteRegister(out_value, address, mask, value));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetProcessActivity(::ams::svc::Handle process_handle, ::ams::svc::ProcessActivity process_activity) {
|
||||
R_RETURN(::svcSetProcessActivity(process_handle, static_cast<::ProcessActivity>(process_activity)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateSharedMemory(::ams::svc::Handle *out_handle, ::ams::svc::Size size, ::ams::svc::MemoryPermission owner_perm, ::ams::svc::MemoryPermission remote_perm) {
|
||||
R_RETURN(::svcCreateSharedMemory(out_handle, size, static_cast<u32>(owner_perm), static_cast<u32>(remote_perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapTransferMemory(::ams::svc::Handle trmem_handle, ::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission owner_perm) {
|
||||
R_RETURN(::svcMapTransferMemory(trmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(owner_perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapTransferMemory(::ams::svc::Handle trmem_handle, ::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcUnmapTransferMemory(trmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateInterruptEvent(::ams::svc::Handle *out_read_handle, int32_t interrupt_id, ::ams::svc::InterruptType interrupt_type) {
|
||||
R_RETURN(::svcCreateInterruptEvent(out_read_handle, interrupt_id, static_cast<u32>(interrupt_type)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result QueryPhysicalAddress(::ams::svc::lp64::PhysicalMemoryInfo *out_info, ::ams::svc::Address address) {
|
||||
R_RETURN(::svcQueryPhysicalAddress(reinterpret_cast<::PhysicalMemoryInfo *>(out_info), address));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result QueryIoMapping(::ams::svc::Address *out_address, ::ams::svc::Size *out_size, ::ams::svc::PhysicalAddress physical_address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcQueryIoMapping(reinterpret_cast<u64 *>(out_address), reinterpret_cast<u64 *>(out_size), physical_address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result LegacyQueryIoMapping(::ams::svc::Address *out_address, ::ams::svc::PhysicalAddress physical_address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcLegacyQueryIoMapping(reinterpret_cast<u64 *>(out_address), physical_address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateDeviceAddressSpace(::ams::svc::Handle *out_handle, uint64_t das_address, uint64_t das_size) {
|
||||
R_RETURN(::svcCreateDeviceAddressSpace(out_handle, das_address, das_size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result AttachDeviceAddressSpace(::ams::svc::DeviceName device_name, ::ams::svc::Handle das_handle) {
|
||||
R_RETURN(::svcAttachDeviceAddressSpace(static_cast<u64>(device_name), das_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result DetachDeviceAddressSpace(::ams::svc::DeviceName device_name, ::ams::svc::Handle das_handle) {
|
||||
R_RETURN(::svcDetachDeviceAddressSpace(static_cast<u64>(device_name), das_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapDeviceAddressSpaceByForce(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, ::ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(::svcMapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, static_cast<u32>(device_perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapDeviceAddressSpaceAligned(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, ::ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(::svcMapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, static_cast<u32>(device_perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapDeviceAddressSpace(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address) {
|
||||
R_RETURN(::svcUnmapDeviceAddressSpace(das_handle, process_handle, process_address, size, device_address));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result InvalidateProcessDataCache(::ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
|
||||
R_RETURN(::svcInvalidateProcessDataCache(process_handle, address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result StoreProcessDataCache(::ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
|
||||
R_RETURN(::svcStoreProcessDataCache(process_handle, address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result FlushProcessDataCache(::ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
|
||||
R_RETURN(::svcFlushProcessDataCache(process_handle, address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result DebugActiveProcess(::ams::svc::Handle *out_handle, uint64_t process_id) {
|
||||
R_RETURN(::svcDebugActiveProcess(out_handle, process_id));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result BreakDebugProcess(::ams::svc::Handle debug_handle) {
|
||||
R_RETURN(::svcBreakDebugProcess(debug_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result TerminateDebugProcess(::ams::svc::Handle debug_handle) {
|
||||
R_RETURN(::svcTerminateDebugProcess(debug_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetDebugEvent(::ams::svc::UserPointer< ::ams::svc::lp64::DebugEventInfo *> out_info, ::ams::svc::Handle debug_handle) {
|
||||
R_RETURN(::svcGetDebugEvent(out_info.GetPointerUnsafe(), debug_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ContinueDebugEvent(::ams::svc::Handle debug_handle, uint32_t flags, ::ams::svc::UserPointer<const uint64_t *> thread_ids, int32_t num_thread_ids) {
|
||||
R_RETURN(::svcContinueDebugEvent(debug_handle, flags, const_cast<u64 *>(thread_ids.GetPointerUnsafe()), num_thread_ids));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result LegacyContinueDebugEvent(::ams::svc::Handle debug_handle, uint32_t flags, uint64_t thread_id) {
|
||||
R_RETURN(::svcLegacyContinueDebugEvent(debug_handle, flags, thread_id));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetProcessList(int32_t *out_num_processes, ::ams::svc::UserPointer<uint64_t *> out_process_ids, int32_t max_out_count) {
|
||||
R_RETURN(::svcGetProcessList(out_num_processes, out_process_ids.GetPointerUnsafe(), max_out_count));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetThreadList(int32_t *out_num_threads, ::ams::svc::UserPointer<uint64_t *> out_thread_ids, int32_t max_out_count, ::ams::svc::Handle debug_handle) {
|
||||
R_RETURN(::svcGetThreadList(out_num_threads, out_thread_ids.GetPointerUnsafe(), max_out_count, debug_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetDebugThreadContext(::ams::svc::UserPointer< ::ams::svc::ThreadContext *> out_context, ::ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) {
|
||||
R_RETURN(::svcGetDebugThreadContext(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), debug_handle, thread_id, context_flags));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetDebugThreadContext(::ams::svc::Handle debug_handle, uint64_t thread_id, ::ams::svc::UserPointer<const ::ams::svc::ThreadContext *> context, uint32_t context_flags) {
|
||||
R_RETURN(::svcSetDebugThreadContext(debug_handle, thread_id, reinterpret_cast<const ::ThreadContext *>(context.GetPointerUnsafe()), context_flags));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result QueryDebugProcessMemory(::ams::svc::UserPointer< ::ams::svc::lp64::MemoryInfo *> out_memory_info, ::ams::svc::PageInfo *out_page_info, ::ams::svc::Handle process_handle, ::ams::svc::Address address) {
|
||||
R_RETURN(::svcQueryDebugProcessMemory(reinterpret_cast<::MemoryInfo *>(out_memory_info.GetPointerUnsafe()), reinterpret_cast<u32 *>(out_page_info), process_handle, address));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ReadDebugProcessMemory(::ams::svc::Address buffer, ::ams::svc::Handle debug_handle, ::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcReadDebugProcessMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(buffer)), debug_handle, address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result WriteDebugProcessMemory(::ams::svc::Handle debug_handle, ::ams::svc::Address buffer, ::ams::svc::Address address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcWriteDebugProcessMemory(debug_handle, reinterpret_cast<const void *>(static_cast<uintptr_t>(buffer)), address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetHardwareBreakPoint(::ams::svc::HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value) {
|
||||
R_RETURN(::svcSetHardwareBreakPoint(static_cast<u32>(name), flags, value));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetDebugThreadParam(uint64_t *out_64, uint32_t *out_32, ::ams::svc::Handle debug_handle, uint64_t thread_id, ::ams::svc::DebugThreadParam param) {
|
||||
R_RETURN(::svcGetDebugThreadParam(out_64, out_32, debug_handle, thread_id, static_cast<::DebugThreadParam>(param)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetSystemInfo(uint64_t *out, ::ams::svc::SystemInfoType info_type, ::ams::svc::Handle handle, uint64_t info_subtype) {
|
||||
R_RETURN(::svcGetSystemInfo(out, static_cast<u64>(info_type), handle, info_subtype));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreatePort(::ams::svc::Handle *out_server_handle, ::ams::svc::Handle *out_client_handle, int32_t max_sessions, bool is_light, ::ams::svc::Address name) {
|
||||
R_RETURN(::svcCreatePort(out_server_handle, out_client_handle, max_sessions, is_light, reinterpret_cast<const char *>(static_cast<uintptr_t>(name))));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ManageNamedPort(::ams::svc::Handle *out_server_handle, ::ams::svc::UserPointer<const char *> name, int32_t max_sessions) {
|
||||
R_RETURN(::svcManageNamedPort(out_server_handle, name.GetPointerUnsafe(), max_sessions));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ConnectToPort(::ams::svc::Handle *out_handle, ::ams::svc::Handle port) {
|
||||
R_RETURN(::svcConnectToPort(out_handle, port));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetProcessMemoryPermission(::ams::svc::Handle process_handle, uint64_t address, uint64_t size, ::ams::svc::MemoryPermission perm) {
|
||||
R_RETURN(::svcSetProcessMemoryPermission(process_handle, address, size, static_cast<u32>(perm)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapProcessMemory(::ams::svc::Address dst_address, ::ams::svc::Handle process_handle, uint64_t src_address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcMapProcessMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), process_handle, src_address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapProcessMemory(::ams::svc::Address dst_address, ::ams::svc::Handle process_handle, uint64_t src_address, ::ams::svc::Size size) {
|
||||
R_RETURN(::svcUnmapProcessMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), process_handle, src_address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result QueryProcessMemory(::ams::svc::UserPointer< ::ams::svc::lp64::MemoryInfo *> out_memory_info, ::ams::svc::PageInfo *out_page_info, ::ams::svc::Handle process_handle, uint64_t address) {
|
||||
R_RETURN(::svcQueryProcessMemory(reinterpret_cast<::MemoryInfo *>(out_memory_info.GetPointerUnsafe()), reinterpret_cast<u32 *>(out_page_info), process_handle, address));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result MapProcessCodeMemory(::ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) {
|
||||
R_RETURN(::svcMapProcessCodeMemory(process_handle, dst_address, src_address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result UnmapProcessCodeMemory(::ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) {
|
||||
R_RETURN(::svcUnmapProcessCodeMemory(process_handle, dst_address, src_address, size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateProcess(::ams::svc::Handle *out_handle, ::ams::svc::UserPointer<const ::ams::svc::lp64::CreateProcessParameter *> parameters, ::ams::svc::UserPointer<const uint32_t *> caps, int32_t num_caps) {
|
||||
R_RETURN(::svcCreateProcess(out_handle, parameters.GetPointerUnsafe(), caps.GetPointerUnsafe(), num_caps));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result StartProcess(::ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) {
|
||||
R_RETURN(::svcStartProcess(process_handle, priority, core_id, main_thread_stack_size));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result TerminateProcess(::ams::svc::Handle process_handle) {
|
||||
R_RETURN(::svcTerminateProcess(process_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result GetProcessInfo(int64_t *out_info, ::ams::svc::Handle process_handle, ::ams::svc::ProcessInfoType info_type) {
|
||||
R_RETURN(::svcGetProcessInfo(out_info, process_handle, static_cast<::ProcessInfoType>(info_type)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result CreateResourceLimit(::ams::svc::Handle *out_handle) {
|
||||
R_RETURN(::svcCreateResourceLimit(out_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result SetResourceLimitLimitValue(::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which, int64_t limit_value) {
|
||||
R_RETURN(::svcSetResourceLimitLimitValue(resource_limit_handle, static_cast<::LimitableResource>(which), limit_value));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void CallSecureMonitor(::ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
::svcCallSecureMonitor(reinterpret_cast<::SecmonArgs *>(args));
|
||||
return ::ams::svc::aarch64::lp64::SetHeapSize(reinterpret_cast<::ams::svc::Address *>(out_address), size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -110,6 +110,66 @@ namespace ams::fssystem {
|
||||
}
|
||||
}
|
||||
|
||||
Result AesCtrCounterExtendedStorage::GetEntryList(Entry *out_entries, s32 *out_entry_count, s32 entry_count, s64 offset, s64 size) {
|
||||
/* Validate pre-conditions. */
|
||||
AMS_ASSERT(offset >= 0);
|
||||
AMS_ASSERT(size >= 0);
|
||||
AMS_ASSERT(this->IsInitialized());
|
||||
|
||||
/* Clear the out count. */
|
||||
R_UNLESS(out_entry_count != nullptr, fs::ResultNullptrArgument());
|
||||
*out_entry_count = 0;
|
||||
|
||||
/* Succeed if there's no range. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* If we have an output array, we need it to be non-null. */
|
||||
R_UNLESS(out_entries != nullptr || entry_count == 0, fs::ResultNullptrArgument());
|
||||
|
||||
/* Check that our range is valid. */
|
||||
BucketTree::Offsets table_offsets;
|
||||
R_TRY(m_table.GetOffsets(std::addressof(table_offsets)));
|
||||
|
||||
R_UNLESS(table_offsets.IsInclude(offset, size), fs::ResultOutOfRange());
|
||||
|
||||
/* Find the offset in our tree. */
|
||||
BucketTree::Visitor visitor;
|
||||
R_TRY(m_table.Find(std::addressof(visitor), offset));
|
||||
{
|
||||
const auto entry_offset = visitor.Get<Entry>()->GetOffset();
|
||||
R_UNLESS(0 <= entry_offset && table_offsets.IsInclude(entry_offset), fs::ResultInvalidAesCtrCounterExtendedEntryOffset());
|
||||
}
|
||||
|
||||
/* Prepare to loop over entries. */
|
||||
const auto end_offset = offset + static_cast<s64>(size);
|
||||
s32 count = 0;
|
||||
|
||||
auto cur_entry = *visitor.Get<Entry>();
|
||||
while (cur_entry.GetOffset() < end_offset) {
|
||||
/* Try to write the entry to the out list */
|
||||
if (entry_count != 0) {
|
||||
if (count >= entry_count) {
|
||||
break;
|
||||
}
|
||||
std::memcpy(out_entries + count, std::addressof(cur_entry), sizeof(Entry));
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
/* Advance. */
|
||||
if (visitor.CanMoveNext()) {
|
||||
R_TRY(visitor.MoveNext());
|
||||
cur_entry = *visitor.Get<Entry>();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the output count. */
|
||||
*out_entry_count = count;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result AesCtrCounterExtendedStorage::Read(s64 offset, void *buffer, size_t size) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(offset >= 0);
|
||||
@@ -126,7 +186,7 @@ namespace ams::fssystem {
|
||||
BucketTree::Offsets table_offsets;
|
||||
R_TRY(m_table.GetOffsets(std::addressof(table_offsets)));
|
||||
|
||||
R_UNLESS(table_offsets.IsInclude(offset, size), fs::ResultOutOfRange());
|
||||
R_UNLESS(table_offsets.IsInclude(offset, size), fs::ResultOutOfRange());
|
||||
|
||||
/* Read the data. */
|
||||
R_TRY(m_data_storage.Read(offset, buffer, size));
|
||||
|
||||
@@ -25,8 +25,19 @@ namespace ams::lr {
|
||||
private:
|
||||
/* Storage for RegisteredData entries by data id. */
|
||||
RegisteredStorages<ncm::DataId, 0x800> m_registered_storages;
|
||||
private:
|
||||
static ALWAYS_INLINE size_t GetStorageCapacity() {
|
||||
const auto version = hos::GetVersion();
|
||||
if (version >= hos::Version_12_0_0) {
|
||||
return 0x8;
|
||||
} else if (version >= hos::Version_9_0_0) {
|
||||
return 0x2;
|
||||
} else {
|
||||
return 0x800;
|
||||
}
|
||||
}
|
||||
public:
|
||||
AddOnContentLocationResolverImpl() : m_registered_storages(hos::GetVersion() < hos::Version_9_0_0 ? 0x800 : 0x2) { /* ... */ }
|
||||
AddOnContentLocationResolverImpl() : m_registered_storages(GetStorageCapacity()) { /* ... */ }
|
||||
|
||||
/* Actual commands. */
|
||||
Result ResolveAddOnContentPath(sf::Out<Path> out, ncm::DataId id);
|
||||
|
||||
@@ -27,7 +27,10 @@ namespace ams::os::impl {
|
||||
AMS_ASSERT(out_size != nullptr);
|
||||
|
||||
/* Get the current stack by NT_TIB */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
auto *tib = reinterpret_cast<NT_TIB *>(::NtCurrentTeb());
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
*out_stack = reinterpret_cast<uintptr_t>(tib->StackLimit);
|
||||
*out_size = reinterpret_cast<uintptr_t>(tib->StackBase) - reinterpret_cast<uintptr_t>(tib->StackLimit);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||
/* Determine svc arguments. */
|
||||
u32 svc_mask = svc::MemoryAttribute_Uncached;
|
||||
u32 svc_attr = 0;
|
||||
|
||||
switch (attr) {
|
||||
case os::MemoryAttribute_Normal: svc_attr = 0; break;
|
||||
case os::MemoryAttribute_Uncached: svc_attr = svc::MemoryAttribute_Uncached; break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
/* Loop, setting attribute. */
|
||||
auto cur_address = address;
|
||||
auto remaining = size;
|
||||
while (remaining > 0) {
|
||||
/* Query the memory. */
|
||||
svc::MemoryInfo mem_info;
|
||||
svc::PageInfo page_info;
|
||||
R_ABORT_UNLESS(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), cur_address));
|
||||
|
||||
/* Determine the current size. */
|
||||
const size_t cur_size = std::min<size_t>(mem_info.base_address + mem_info.size - cur_address, remaining);
|
||||
|
||||
/* Set the attribute, if necessary. */
|
||||
if (mem_info.attribute != svc_attr) {
|
||||
if (const auto res = svc::SetMemoryAttribute(address, size, svc_mask, svc_attr); R_FAILED(res)) {
|
||||
/* NOTE: Nintendo logs here. */
|
||||
R_ABORT_UNLESS(res);
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address += cur_size;
|
||||
remaining -= cur_size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||
/* TODO: Should this do anything? */
|
||||
AMS_UNUSED(address, size, attr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||
/* TODO: Should this do anything? */
|
||||
AMS_UNUSED(address, size, attr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||
/* TODO: Should this do anything? */
|
||||
AMS_UNUSED(address, size, attr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "os_memory_heap_manager.hpp"
|
||||
#include "os_thread_manager.hpp"
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
Result MemoryHeapManager::SetHeapSize(size_t size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(util::IsAligned(size, MemoryHeapUnitSize));
|
||||
|
||||
/* Acquire locks. */
|
||||
std::scoped_lock lk1(util::GetReference(::ams::os::impl::GetCurrentThread()->cs_thread));
|
||||
std::scoped_lock lk2(m_cs);
|
||||
|
||||
/* If we need to, expand the heap. */
|
||||
if (size > m_heap_size) {
|
||||
/* Set the new heap size. */
|
||||
uintptr_t address = 0;
|
||||
R_TRY(m_impl.SetHeapSize(std::addressof(address), size));
|
||||
R_UNLESS(address != 0, os::ResultOutOfMemory());
|
||||
|
||||
/* Check that the new heap address is consistent. */
|
||||
if (m_heap_size == 0) {
|
||||
AMS_ASSERT(util::IsAligned(address, MemoryHeapUnitSize));
|
||||
} else {
|
||||
AMS_ASSERT(address == m_heap_address);
|
||||
}
|
||||
|
||||
/* Set up the new heap address. */
|
||||
this->AddToFreeSpaceUnsafe(address + m_heap_size, size - m_heap_size);
|
||||
|
||||
/* Set our heap address. */
|
||||
m_heap_address = address;
|
||||
m_heap_size = size;
|
||||
} else if (size < m_heap_size) {
|
||||
/* We're shrinking the heap, so we need to remove memory blocks. */
|
||||
const uintptr_t end_address = m_heap_address + size;
|
||||
const size_t remove_size = m_heap_size - size;
|
||||
|
||||
/* Get the end of the heap. */
|
||||
auto it = m_free_memory_list.end();
|
||||
--it;
|
||||
R_UNLESS(it != m_free_memory_list.end(), os::ResultBusy());
|
||||
|
||||
/* Check that the block can be decommitted. */
|
||||
R_UNLESS(it->GetAddress() <= end_address, os::ResultBusy());
|
||||
R_UNLESS(it->GetSize() >= remove_size, os::ResultBusy());
|
||||
|
||||
/* Adjust the last node. */
|
||||
if (const size_t node_size = it->GetSize() - remove_size; node_size == 0) {
|
||||
m_free_memory_list.erase(it);
|
||||
it->Clean();
|
||||
} else {
|
||||
it->SetSize(node_size);
|
||||
}
|
||||
|
||||
/* Set the reduced heap size. */
|
||||
uintptr_t address = 0;
|
||||
R_ABORT_UNLESS(m_impl.SetHeapSize(std::addressof(address), size));
|
||||
|
||||
/* Set our heap address. */
|
||||
m_heap_size = size;
|
||||
if (size == 0) {
|
||||
m_heap_address = 0;
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemoryHeapManager::AllocateFromHeap(uintptr_t *out_address, size_t size) {
|
||||
/* Acquire locks. */
|
||||
std::scoped_lock lk1(util::GetReference(::ams::os::impl::GetCurrentThread()->cs_thread));
|
||||
std::scoped_lock lk2(m_cs);
|
||||
|
||||
/* Find free space. */
|
||||
auto it = this->FindFreeSpaceUnsafe(size);
|
||||
R_UNLESS(it != m_free_memory_list.end(), os::ResultOutOfMemory());
|
||||
|
||||
/* If necessary, split the memory block. */
|
||||
if (it->GetSize() > size) {
|
||||
this->SplitFreeMemoryNodeUnsafe(it, size);
|
||||
}
|
||||
|
||||
/* Remove the block. */
|
||||
m_free_memory_list.erase(it);
|
||||
it->Clean();
|
||||
|
||||
/* Increment the used heap size. */
|
||||
m_used_heap_size += size;
|
||||
|
||||
/* Set the output address. */
|
||||
*out_address = it->GetAddress();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void MemoryHeapManager::ReleaseToHeap(uintptr_t address, size_t size) {
|
||||
/* Acquire locks. */
|
||||
std::scoped_lock lk1(util::GetReference(::ams::os::impl::GetCurrentThread()->cs_thread));
|
||||
std::scoped_lock lk2(m_cs);
|
||||
|
||||
/* Check pre-condition. */
|
||||
AMS_ABORT_UNLESS(this->IsRegionAllocatedMemoryUnsafe(address, size));
|
||||
|
||||
/* Restore the permissions on the memory. */
|
||||
os::SetMemoryPermission(address, size, MemoryPermission_ReadWrite);
|
||||
os::SetMemoryAttribute(address, size, MemoryAttribute_Normal);
|
||||
|
||||
/* Add the memory back to our free list. */
|
||||
this->AddToFreeSpaceUnsafe(address, size);
|
||||
|
||||
/* Decrement the used heap size. */
|
||||
m_used_heap_size -= size;
|
||||
}
|
||||
|
||||
MemoryHeapManager::FreeMemoryList::iterator MemoryHeapManager::FindFreeSpaceUnsafe(size_t size) {
|
||||
/* Find the best fit candidate. */
|
||||
auto best = m_free_memory_list.end();
|
||||
|
||||
for (auto it = m_free_memory_list.begin(); it != m_free_memory_list.end(); ++it) {
|
||||
if (const size_t node_size = it->GetSize(); node_size >= size) {
|
||||
if (best == m_free_memory_list.end() || node_size < best->GetSize()) {
|
||||
best = it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
MemoryHeapManager::FreeMemoryList::iterator MemoryHeapManager::ConcatenatePreviousFreeMemoryNodeUnsafe(FreeMemoryList::iterator node) {
|
||||
/* Get the previous node. */
|
||||
auto prev = node;
|
||||
--prev;
|
||||
|
||||
/* If there's no previous, we're done. */
|
||||
if (prev == m_free_memory_list.end() || node == m_free_memory_list.end()) {
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Otherwise, if the previous isn't contiguous, we can't merge. */
|
||||
if (prev->GetAddress() + prev->GetSize() != node->GetAddress()) {
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Otherwise, increase the size of the previous node, and remove the current node. */
|
||||
prev->SetSize(prev->GetSize() + node->GetSize());
|
||||
m_free_memory_list.erase(node);
|
||||
node->Clean();
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void MemoryHeapManager::SplitFreeMemoryNodeUnsafe(FreeMemoryList::iterator it, size_t size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(it->GetSize() > size);
|
||||
AMS_ASSERT(util::IsAligned(size, MemoryBlockUnitSize));
|
||||
|
||||
/* Create new node. */
|
||||
auto *new_node = std::construct_at(reinterpret_cast<FreeMemoryNode *>(it->GetAddress() + size));
|
||||
new_node->SetSize(it->GetSize() - size);
|
||||
|
||||
/* Set the old node's size. */
|
||||
it->SetSize(size);
|
||||
|
||||
/* Insert the new node. */
|
||||
m_free_memory_list.insert(++it, *new_node);
|
||||
}
|
||||
|
||||
void MemoryHeapManager::AddToFreeSpaceUnsafe(uintptr_t address, size_t size) {
|
||||
/* Create new node. */
|
||||
auto *new_node = std::construct_at(reinterpret_cast<FreeMemoryNode *>(address));
|
||||
new_node->SetSize(size);
|
||||
|
||||
/* Find the appropriate place to insert the node. */
|
||||
auto it = m_free_memory_list.begin();
|
||||
for (/* ... */; it != m_free_memory_list.end(); ++it) {
|
||||
if (address < it->GetAddress()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert the new node. */
|
||||
it = m_free_memory_list.insert(it, *new_node);
|
||||
|
||||
/* Perform coalescing as relevant. */
|
||||
it = this->ConcatenatePreviousFreeMemoryNodeUnsafe(it);
|
||||
this->ConcatenatePreviousFreeMemoryNodeUnsafe(++it);
|
||||
}
|
||||
|
||||
bool MemoryHeapManager::IsRegionAllocatedMemoryUnsafe(uintptr_t address, size_t size) {
|
||||
/* Look for a node containing the region. */
|
||||
for (auto it = m_free_memory_list.begin(); it != m_free_memory_list.end(); ++it) {
|
||||
const uintptr_t node_address = it->GetAddress();
|
||||
const size_t node_size = it->GetSize();
|
||||
|
||||
if (node_address < address + size && address < node_address + node_size) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "os_memory_heap_manager_types.hpp"
|
||||
#include "os_resource_manager.hpp"
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
ALWAYS_INLINE MemoryHeapManager &GetMemoryHeapManager() {
|
||||
return GetResourceManager().GetMemoryHeapManager();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class MemoryHeapManagerHorizonImpl {
|
||||
public:
|
||||
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||
R_TRY_CATCH(svc::SetHeapSize(out, size)) {
|
||||
R_CONVERT(svc::ResultOutOfMemory, os::ResultOutOfMemory())
|
||||
R_CONVERT(svc::ResultLimitReached, os::ResultOutOfMemory())
|
||||
R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfMemory())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
};
|
||||
|
||||
using MemoryHeapManagerImpl = MemoryHeapManagerHorizonImpl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class MemoryHeapManagerLinuxImpl {
|
||||
NON_COPYABLE(MemoryHeapManagerLinuxImpl);
|
||||
NON_MOVEABLE(MemoryHeapManagerLinuxImpl);
|
||||
private:
|
||||
uintptr_t m_real_reserved_address;
|
||||
size_t m_real_reserved_size;
|
||||
uintptr_t m_aligned_reserved_heap_address;
|
||||
size_t m_aligned_reserved_heap_size;
|
||||
size_t m_committed_size;
|
||||
public:
|
||||
MemoryHeapManagerLinuxImpl() : m_real_reserved_address(0), m_real_reserved_size(0), m_aligned_reserved_heap_address(0), m_aligned_reserved_heap_size(0), m_committed_size(0) {
|
||||
/* Reserve a 32 GB region of virtual address space. */
|
||||
constexpr size_t TargetReservedSize = 32_GB;
|
||||
const auto reserved = ::mmap(nullptr, TargetReservedSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||
|
||||
m_real_reserved_address = reinterpret_cast<uintptr_t>(reserved);
|
||||
m_real_reserved_size = TargetReservedSize;
|
||||
|
||||
m_aligned_reserved_heap_address = util::AlignUp(m_real_reserved_address, MemoryHeapUnitSize);
|
||||
m_aligned_reserved_heap_size = m_real_reserved_size - MemoryHeapUnitSize;
|
||||
}
|
||||
|
||||
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||
/* Check that we have a reserved address. */
|
||||
R_UNLESS(m_real_reserved_address != 0, os::ResultOutOfMemory());
|
||||
|
||||
/* If necessary, commit the new memory. */
|
||||
if (size > m_committed_size) {
|
||||
R_UNLESS(this->CommitMemory(size), os::ResultOutOfMemory());
|
||||
} else if (size < m_committed_size) {
|
||||
/* Otherwise, decommit. */
|
||||
this->DecommitMemory(m_aligned_reserved_heap_address + size, m_committed_size - size);
|
||||
}
|
||||
|
||||
/* Set the committed size. */
|
||||
m_committed_size = size;
|
||||
|
||||
/* Set the out address. */
|
||||
*out = m_aligned_reserved_heap_address;
|
||||
R_SUCCEED();
|
||||
}
|
||||
private:
|
||||
bool CommitMemory(size_t size) {
|
||||
const auto res = ::mprotect(reinterpret_cast<void *>(m_aligned_reserved_heap_address), size, PROT_READ | PROT_WRITE);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
void DecommitMemory(uintptr_t address, size_t size) {
|
||||
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||
}
|
||||
};
|
||||
|
||||
using MemoryHeapManagerImpl = MemoryHeapManagerLinuxImpl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class MemoryHeapManagerMacosImpl {
|
||||
NON_COPYABLE(MemoryHeapManagerMacosImpl);
|
||||
NON_MOVEABLE(MemoryHeapManagerMacosImpl);
|
||||
private:
|
||||
uintptr_t m_real_reserved_address;
|
||||
size_t m_real_reserved_size;
|
||||
uintptr_t m_aligned_reserved_heap_address;
|
||||
size_t m_aligned_reserved_heap_size;
|
||||
size_t m_committed_size;
|
||||
public:
|
||||
MemoryHeapManagerMacosImpl() : m_real_reserved_address(0), m_real_reserved_size(0), m_aligned_reserved_heap_address(0), m_aligned_reserved_heap_size(0), m_committed_size(0) {
|
||||
/* Reserve a 32 GB region of virtual address space. */
|
||||
constexpr size_t TargetReservedSize = 32_GB;
|
||||
const auto reserved = ::mmap(nullptr, TargetReservedSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||
|
||||
m_real_reserved_address = reinterpret_cast<uintptr_t>(reserved);
|
||||
m_real_reserved_size = TargetReservedSize;
|
||||
|
||||
m_aligned_reserved_heap_address = util::AlignUp(m_real_reserved_address, MemoryHeapUnitSize);
|
||||
m_aligned_reserved_heap_size = m_real_reserved_size - MemoryHeapUnitSize;
|
||||
}
|
||||
|
||||
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||
/* Check that we have a reserved address. */
|
||||
R_UNLESS(m_real_reserved_address != 0, os::ResultOutOfMemory());
|
||||
|
||||
/* If necessary, commit the new memory. */
|
||||
if (size > m_committed_size) {
|
||||
R_UNLESS(this->CommitMemory(size), os::ResultOutOfMemory());
|
||||
} else if (size < m_committed_size) {
|
||||
/* Otherwise, decommit. */
|
||||
this->DecommitMemory(m_aligned_reserved_heap_address + size, m_committed_size - size);
|
||||
}
|
||||
|
||||
/* Set the committed size. */
|
||||
m_committed_size = size;
|
||||
|
||||
/* Set the out address. */
|
||||
*out = m_aligned_reserved_heap_address;
|
||||
R_SUCCEED();
|
||||
}
|
||||
private:
|
||||
bool CommitMemory(size_t size) {
|
||||
const auto res = ::mprotect(reinterpret_cast<void *>(m_aligned_reserved_heap_address), size, PROT_READ | PROT_WRITE);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
void DecommitMemory(uintptr_t address, size_t size) {
|
||||
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||
}
|
||||
};
|
||||
|
||||
using MemoryHeapManagerImpl = MemoryHeapManagerMacosImpl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include <stratosphere/windows.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class MemoryHeapManagerWindowsImpl {
|
||||
NON_COPYABLE(MemoryHeapManagerWindowsImpl);
|
||||
NON_MOVEABLE(MemoryHeapManagerWindowsImpl);
|
||||
private:
|
||||
LPVOID m_real_reserved_address;
|
||||
size_t m_real_reserved_size;
|
||||
LPVOID m_aligned_reserved_heap_address;
|
||||
size_t m_aligned_reserved_heap_size;
|
||||
size_t m_committed_size;
|
||||
public:
|
||||
MemoryHeapManagerWindowsImpl() : m_real_reserved_address(nullptr), m_real_reserved_size(0), m_aligned_reserved_heap_address(nullptr), m_aligned_reserved_heap_size(0), m_committed_size(0) {
|
||||
/* Define target size. */
|
||||
constexpr size_t TargetReservedSize = 32_GB;
|
||||
|
||||
/* Allocate appropriate amount of virtual space. */
|
||||
size_t reserved_size = 0;
|
||||
size_t reserved_addend = TargetReservedSize;
|
||||
while (reserved_addend >= MemoryHeapUnitSize) {
|
||||
if (this->ReserveVirtualSpace(0, reserved_size + reserved_addend)) {
|
||||
this->ReleaseVirtualSpace();
|
||||
|
||||
reserved_size += reserved_addend;
|
||||
if (reserved_size >= TargetReservedSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reserved_addend /= 2;
|
||||
}
|
||||
|
||||
/* Reserve virtual space. */
|
||||
AMS_ABORT_UNLESS(this->ReserveVirtualSpace(0, reserved_size));
|
||||
}
|
||||
|
||||
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||
/* Check that we have a reserved address. */
|
||||
R_UNLESS(m_real_reserved_address != nullptr, os::ResultOutOfMemory());
|
||||
|
||||
/* If necessary, commit the new memory. */
|
||||
if (size > m_committed_size) {
|
||||
R_UNLESS(this->CommitMemory(size), os::ResultOutOfMemory());
|
||||
} else if (size < m_committed_size) {
|
||||
/* Otherwise, decommit. */
|
||||
this->DecommitMemory(reinterpret_cast<uintptr_t>(m_aligned_reserved_heap_address) + size, m_committed_size - size);
|
||||
}
|
||||
|
||||
/* Set the committed size. */
|
||||
m_committed_size = size;
|
||||
|
||||
/* Set the out address. */
|
||||
*out = reinterpret_cast<uintptr_t>(m_aligned_reserved_heap_address);
|
||||
R_SUCCEED();
|
||||
}
|
||||
private:
|
||||
bool ReserveVirtualSpace(uintptr_t address, size_t size) {
|
||||
AMS_ABORT_UNLESS(m_real_reserved_address == nullptr);
|
||||
AMS_ABORT_UNLESS(m_real_reserved_size == 0);
|
||||
|
||||
size_t reserve_size = util::AlignUp(size, MemoryHeapUnitSize);
|
||||
if constexpr (constexpr size_t VirtualAllocUnitSize = 64_KB; MemoryHeapUnitSize > VirtualAllocUnitSize) {
|
||||
reserve_size += MemoryHeapUnitSize - VirtualAllocUnitSize;
|
||||
}
|
||||
|
||||
LPVOID res = ::VirtualAlloc(reinterpret_cast<LPVOID>(address), reserve_size, MEM_RESERVE, PAGE_READWRITE);
|
||||
if (res == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_real_reserved_address = res;
|
||||
m_real_reserved_size = reserve_size;
|
||||
|
||||
m_aligned_reserved_heap_address = reinterpret_cast<LPVOID>(util::AlignUp(reinterpret_cast<uintptr_t>(m_real_reserved_address), MemoryHeapUnitSize));
|
||||
m_aligned_reserved_heap_size = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReleaseVirtualSpace() {
|
||||
if (m_real_reserved_address != nullptr) {
|
||||
auto res = ::VirtualFree(m_real_reserved_address, 0, MEM_RELEASE);
|
||||
AMS_ASSERT(res);
|
||||
AMS_UNUSED(res);
|
||||
|
||||
m_real_reserved_address = nullptr;
|
||||
m_real_reserved_size = 0;
|
||||
|
||||
m_aligned_reserved_heap_address = nullptr;
|
||||
m_aligned_reserved_heap_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CommitMemory(size_t size) {
|
||||
LPVOID address = ::VirtualAlloc(m_aligned_reserved_heap_address, static_cast<SIZE_T>(size), MEM_COMMIT, PAGE_READWRITE);
|
||||
if (address == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AMS_ABORT_UNLESS(address == m_aligned_reserved_heap_address);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DecommitMemory(uintptr_t address, size_t size) {
|
||||
auto res = ::VirtualFree(reinterpret_cast<LPVOID>(address), static_cast<SIZE_T>(size), MEM_DECOMMIT);
|
||||
AMS_ASSERT(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
};
|
||||
|
||||
using MemoryHeapManagerImpl = MemoryHeapManagerWindowsImpl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include "os_memory_heap_manager_impl.os.horizon.hpp"
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
#include "os_memory_heap_manager_impl.os.windows.hpp"
|
||||
#elif defined(ATMOSPHERE_OS_LINUX)
|
||||
#include "os_memory_heap_manager_impl.os.linux.hpp"
|
||||
#elif defined(ATMOSPHERE_OS_MACOS)
|
||||
#include "os_memory_heap_manager_impl.os.macos.hpp"
|
||||
#else
|
||||
#error "Unknown OS for MemoryHeapManagerImpl"
|
||||
#endif
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class MemoryHeapManager;
|
||||
|
||||
class FreeMemoryNode {
|
||||
private:
|
||||
friend class MemoryHeapManager;
|
||||
private:
|
||||
util::IntrusiveListNode m_node;
|
||||
size_t m_size;
|
||||
public:
|
||||
ALWAYS_INLINE uintptr_t GetAddress() const { return reinterpret_cast<uintptr_t>(this); }
|
||||
ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||
ALWAYS_INLINE void SetSize(size_t size) { m_size = size; }
|
||||
ALWAYS_INLINE void Clean() { std::memset(reinterpret_cast<void *>(this), 0, sizeof(FreeMemoryNode)); }
|
||||
};
|
||||
static_assert(sizeof(FreeMemoryNode) == sizeof(util::IntrusiveListNode) + sizeof(size_t));
|
||||
|
||||
class MemoryHeapManager {
|
||||
NON_COPYABLE(MemoryHeapManager);
|
||||
NON_MOVEABLE(MemoryHeapManager);
|
||||
private:
|
||||
using FreeMemoryList = typename util::IntrusiveListMemberTraits<&FreeMemoryNode::m_node>::ListType;
|
||||
private:
|
||||
uintptr_t m_heap_address;
|
||||
size_t m_heap_size;
|
||||
size_t m_used_heap_size;
|
||||
FreeMemoryList m_free_memory_list;
|
||||
InternalCriticalSection m_cs;
|
||||
MemoryHeapManagerImpl m_impl;
|
||||
public:
|
||||
MemoryHeapManager() : m_heap_address(0), m_heap_size(0), m_used_heap_size(0) { /* ... */ }
|
||||
|
||||
Result SetHeapSize(size_t size);
|
||||
|
||||
Result AllocateFromHeap(uintptr_t *out_address, size_t size);
|
||||
void ReleaseToHeap(uintptr_t address, size_t size);
|
||||
|
||||
bool IsRegionInMemoryHeap(uintptr_t address, size_t size) const {
|
||||
return m_heap_address <= address && (address + size) <= (m_heap_address + m_heap_size);
|
||||
}
|
||||
|
||||
uintptr_t GetHeapAddress() const { return m_heap_address; }
|
||||
size_t GetHeapSize() const { return m_heap_size; }
|
||||
size_t GetUsedHeapSize() const { return m_used_heap_size; }
|
||||
private:
|
||||
FreeMemoryList::iterator FindFreeSpaceUnsafe(size_t size);
|
||||
FreeMemoryList::iterator ConcatenatePreviousFreeMemoryNodeUnsafe(FreeMemoryList::iterator node);
|
||||
void SplitFreeMemoryNodeUnsafe(FreeMemoryList::iterator it, size_t size);
|
||||
void AddToFreeSpaceUnsafe(uintptr_t address, size_t size);
|
||||
bool IsRegionAllocatedMemoryUnsafe(uintptr_t address, size_t size);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryPermissionImpl(uintptr_t address, size_t size, MemoryPermission perm) {
|
||||
switch (perm) {
|
||||
case MemoryPermission_None:
|
||||
{
|
||||
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE);
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
case MemoryPermission_ReadOnly:
|
||||
{
|
||||
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ);
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
case MemoryPermission_ReadWrite:
|
||||
{
|
||||
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ | PROT_WRITE);
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryPermissionImpl(uintptr_t address, size_t size, MemoryPermission perm) {
|
||||
switch (perm) {
|
||||
case MemoryPermission_None:
|
||||
{
|
||||
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE);
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
case MemoryPermission_ReadOnly:
|
||||
{
|
||||
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ);
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
case MemoryPermission_ReadWrite:
|
||||
{
|
||||
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ | PROT_WRITE);
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include <stratosphere/windows.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
void SetMemoryPermissionImpl(uintptr_t address, size_t size, MemoryPermission perm) {
|
||||
DWORD old;
|
||||
|
||||
uintptr_t cur_address = address;
|
||||
size_t remaining = size;
|
||||
while (remaining > 0) {
|
||||
const size_t cur_size = std::min<size_t>(remaining, 2_GB);
|
||||
switch (perm) {
|
||||
case MemoryPermission_None:
|
||||
{
|
||||
auto res = ::VirtualProtect(reinterpret_cast<LPVOID>(cur_address), static_cast<DWORD>(cur_size), PAGE_NOACCESS, std::addressof(old));
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
case MemoryPermission_ReadOnly:
|
||||
{
|
||||
auto res = ::VirtualProtect(reinterpret_cast<LPVOID>(cur_address), static_cast<DWORD>(cur_size), PAGE_READONLY, std::addressof(old));
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
case MemoryPermission_ReadWrite:
|
||||
{
|
||||
auto res = ::VirtualProtect(reinterpret_cast<LPVOID>(cur_address), static_cast<DWORD>(cur_size), PAGE_READWRITE, std::addressof(old));
|
||||
AMS_ABORT_UNLESS(res);
|
||||
AMS_UNUSED(res);
|
||||
}
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
cur_address += cur_size;
|
||||
remaining -= cur_size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "os_aslr_space_manager_types.hpp"
|
||||
#include "os_tls_manager_types.hpp"
|
||||
#include "os_giant_lock_types.hpp"
|
||||
#include "os_memory_heap_manager_types.hpp"
|
||||
#include "os_vamm_manager_types.hpp"
|
||||
|
||||
namespace ams::os::impl {
|
||||
@@ -34,7 +35,7 @@ namespace ams::os::impl {
|
||||
ThreadManager m_thread_manager{};
|
||||
//TlsManager m_tls_manager{};
|
||||
TickManager m_tick_manager{};
|
||||
/* TODO */
|
||||
MemoryHeapManager m_memory_heap_manager;
|
||||
VammManager m_vamm_manager;
|
||||
GiantLock m_giant_lock{};
|
||||
public:
|
||||
@@ -46,6 +47,7 @@ namespace ams::os::impl {
|
||||
constexpr ALWAYS_INLINE StackGuardManager &GetStackGuardManager() { return m_stack_guard_manager; }
|
||||
//constexpr ALWAYS_INLINE TlsManager &GetTlsManager() { return m_tls_manager; }
|
||||
constexpr ALWAYS_INLINE TickManager &GetTickManager() { return m_tick_manager; }
|
||||
constexpr ALWAYS_INLINE MemoryHeapManager &GetMemoryHeapManager() { return m_memory_heap_manager; }
|
||||
constexpr ALWAYS_INLINE VammManager &GetVammManager() { return m_vamm_manager; }
|
||||
constexpr ALWAYS_INLINE GiantLock &GetGiantLock() { return m_giant_lock; }
|
||||
};
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace ams::os::impl {
|
||||
}
|
||||
|
||||
static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
||||
R_UNLESS(::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE) == 0, os::ResultBusy());
|
||||
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
R_UNLESS(reserved != MAP_FAILED, os::ResultBusy());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace ams::os::impl {
|
||||
}
|
||||
|
||||
static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
||||
R_UNLESS(::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE) == 0, os::ResultBusy());
|
||||
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
R_UNLESS(reserved != MAP_FAILED, os::ResultBusy());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
29
libraries/libstratosphere/source/os/os_memory_attribute.cpp
Normal file
29
libraries/libstratosphere/source/os/os_memory_attribute.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "impl/os_memory_attribute_impl.hpp"
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
void SetMemoryAttribute(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(util::IsAligned(address, MemoryPageSize));
|
||||
AMS_ASSERT(util::IsAligned(size, MemoryPageSize));
|
||||
|
||||
return impl::SetMemoryAttributeImpl(address, size, attr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,17 +14,47 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "impl/os_memory_heap_manager.hpp"
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
Result SetMemoryHeapSize(size_t size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(util::IsAligned(size, MemoryHeapUnitSize));
|
||||
|
||||
/* Set the heap size. */
|
||||
R_RETURN(impl::GetMemoryHeapManager().SetHeapSize(size));
|
||||
}
|
||||
|
||||
uintptr_t GetMemoryHeapAddress() {
|
||||
return impl::GetMemoryHeapManager().GetHeapAddress();
|
||||
}
|
||||
|
||||
size_t GetMemoryHeapSize() {
|
||||
return impl::GetMemoryHeapManager().GetHeapSize();
|
||||
}
|
||||
|
||||
Result AllocateMemoryBlock(uintptr_t *out_address, size_t size) {
|
||||
AMS_UNUSED(out_address, size);
|
||||
AMS_ABORT("Not implemented yet");
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(size > 0);
|
||||
AMS_ASSERT(util::IsAligned(size, MemoryBlockUnitSize));
|
||||
|
||||
/* Allocate from heap. */
|
||||
R_RETURN(impl::GetMemoryHeapManager().AllocateFromHeap(out_address, size));
|
||||
}
|
||||
|
||||
void FreeMemoryBlock(uintptr_t address, size_t size) {
|
||||
AMS_UNUSED(address, size);
|
||||
AMS_ABORT("Not implemented yet");
|
||||
/* Get memory heap manager. */
|
||||
auto &manager = impl::GetMemoryHeapManager();
|
||||
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(util::IsAligned(address, MemoryBlockUnitSize));
|
||||
AMS_ASSERT(size > 0);
|
||||
AMS_ASSERT(util::IsAligned(size, MemoryBlockUnitSize));
|
||||
AMS_ABORT_UNLESS(manager.IsRegionInMemoryHeap(address, size));
|
||||
|
||||
/* Release the memory block. */
|
||||
manager.ReleaseToHeap(address, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
.section .text._ZN3ams3svc7aarch644lp6412CreateIoPoolEPjNS0_5board8nintendo2nx10IoPoolTypeE, "ax", %progbits
|
||||
.global _ZN3ams3svc7aarch644lp6412CreateIoPoolEPjNS0_5board8nintendo2nx10IoPoolTypeE
|
||||
.type _ZN3ams3svc7aarch644lp6412CreateIoPoolEPjNS0_5board8nintendo2nx10IoPoolTypeE, %function
|
||||
.align 2
|
||||
.cfi_startproc
|
||||
_ZN3ams3svc7aarch644lp6412CreateIoPoolEPjNS0_5board8nintendo2nx10IoPoolTypeE:
|
||||
str x0, [sp, #-16]!
|
||||
svc 0x39
|
||||
ldr x2, [sp], #16
|
||||
str w1, [x2]
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.section .text._ZN3ams3svc7aarch644lp6424AttachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj, "ax", %progbits
|
||||
.global _ZN3ams3svc7aarch644lp6424AttachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj
|
||||
.type _ZN3ams3svc7aarch644lp6424AttachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj, %function
|
||||
.align 2
|
||||
.cfi_startproc
|
||||
_ZN3ams3svc7aarch644lp6424AttachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj:
|
||||
svc 0x57
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.section .text._ZN3ams3svc7aarch644lp6424DetachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj, "ax", %progbits
|
||||
.global _ZN3ams3svc7aarch644lp6424DetachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj
|
||||
.type _ZN3ams3svc7aarch644lp6424DetachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj, %function
|
||||
.align 2
|
||||
.cfi_startproc
|
||||
_ZN3ams3svc7aarch644lp6424DetachDeviceAddressSpaceENS0_5board8nintendo2nx10DeviceNameEj:
|
||||
svc 0x58
|
||||
ret
|
||||
.cfi_endproc
|
||||
@@ -2353,8 +2353,33 @@ namespace ams::dmnt {
|
||||
m_debug_process.GetThreadName(name, thread_ids[i]);
|
||||
name[sizeof(name) - 1] = '\x00';
|
||||
|
||||
/* Sanitize the thread name. */
|
||||
char sanitized[os::ThreadNameLengthMax * 4 + 1];
|
||||
{
|
||||
char *cur = sanitized;
|
||||
for (size_t i = 0; i < util::size(name); ++i) {
|
||||
if (name[i] == '<') {
|
||||
*(cur++) = '&';
|
||||
*(cur++) = 'l';
|
||||
*(cur++) = 't';
|
||||
*(cur++) = ';';
|
||||
} else if (name[i] == '>') {
|
||||
*(cur++) = '&';
|
||||
*(cur++) = 'g';
|
||||
*(cur++) = 't';
|
||||
*(cur++) = ';';
|
||||
} else {
|
||||
*(cur++) = name[i];
|
||||
|
||||
if (name[i] == '\x00') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the thread entry */
|
||||
AppendReplyFormat(dst_cur, dst_end, "<thread id=\"p%lx.%lx\" core=\"%u\" name=\"%s\" />", m_process_id.value, thread_ids[i], core, name);
|
||||
AppendReplyFormat(dst_cur, dst_end, "<thread id=\"p%lx.%lx\" core=\"%u\" name=\"%s\" />", m_process_id.value, thread_ids[i], core, sanitized);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user