Compare commits

...

12 Commits

Author SHA1 Message Date
Michael Scire
070d2786c6 strat: add explicit namespaced svc accessors 2022-06-15 13:00:36 -07:00
Michael Scire
efa4a346af os: silence warning building with gcc 12 on windows 2022-06-12 01:38:04 -07:00
Michael Scire
d75f9bbedf fs: add extension GetEntryList to AesCtrCounterExtendedStorage 2022-06-11 16:54:02 -07:00
Michael Scire
ea7f51a279 os: fix whoops in SetMemoryPermission on windows 2022-06-11 00:58:14 -07:00
Michael Scire
a65b6df8d2 os: implement MemoryHeapManager, SetMemoryAttribute 2022-06-10 22:36:03 -07:00
Michael Scire
4e112de223 dmnt.gen2: fix gt, optimize 2022-06-08 00:49:47 -07:00
Michael Scire
20d200471d kern: optimize postfix-compare to prefix-compare, result logic is identical but breaks earlier in some paths 2022-06-07 23:49:31 -07:00
Michael Scire
5f2d713fe4 kern: mea culpa (some time since 7.x) 2022-06-07 23:40:32 -07:00
Michael Scire
114d2598da dmnt.gen2: sanitize brackets in thread names to be valid xml 2022-06-07 22:03:37 -07:00
Michael Scire
36bdb83cfc util: prevent optimizer from removing endian-swapped writes 2022-06-05 22:57:18 -07:00
Michael Scire
a975689c59 ams: address some warnings when building with gcc-12 2022-06-05 22:57:08 -07:00
Michael Scire
a809e23320 lr: update capacity constants to reflect 12.0.0 changes 2022-05-26 18:44:12 -07:00
40 changed files with 2625 additions and 502 deletions

View File

@@ -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;
}
}

View File

@@ -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);
};

View File

@@ -843,7 +843,7 @@ namespace ams::ncm {
R_SUCCEED_IF(m_header.has_value());
/* Get our header. */
PatchMetaExtendedDataHeader header;
PatchMetaExtendedDataHeader header{};
R_TRY(this->GetHeader(std::addressof(header)));
/* Set our header. */

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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),

View File

@@ -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>

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -148,6 +148,8 @@ init_libnx_shim.os.horizon.o: CXXFLAGS += -fno-lto
result_get_name.o: CXXFLAGS += -fno-lto
crypto_sha256_generator.o: CXXFLAGS += -fno-lto
spl_secure_monitor_api.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include
fs_id_string_impl.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
};
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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; }
};

View File

@@ -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();
}

View File

@@ -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();
}

View 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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -47,9 +47,9 @@ namespace ams::crypto {
};
static constexpr size_t Asn1IdentifierSize = util::size(Asn1Identifier);
private:
Impl m_impl;
Impl m_impl{};
public:
Sha256Generator() { /* ... */ }
Sha256Generator() = default;
void Initialize() {
m_impl.Initialize();

View File

@@ -144,12 +144,12 @@ namespace ams::util {
template<std::integral T>
constexpr ALWAYS_INLINE void StoreBigEndian(T *ptr, T val) {
*ptr = ConvertToBigEndian<T>(val);
*static_cast<volatile T *>(ptr) = ConvertToBigEndian<T>(val);
}
template<std::integral T>
constexpr ALWAYS_INLINE void StoreLittleEndian(T *ptr, T val) {
*ptr = ConvertToLittleEndian<T>(val);
*static_cast<volatile T *>(ptr) = ConvertToLittleEndian<T>(val);
}
}

View File

@@ -18,7 +18,7 @@
namespace ams::crypto {
void GenerateSha256(void *dst, size_t dst_size, const void *src, size_t src_size) {
Sha256Generator gen;
Sha256Generator gen{};
gen.Initialize();
gen.Update(src, src_size);

View File

@@ -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);
}
}