summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/client_port.cpp4
-rw-r--r--src/core/hle/kernel/client_session.cpp4
-rw-r--r--src/core/hle/kernel/errors.h43
-rw-r--r--src/core/hle/kernel/handle_table.cpp10
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp2
-rw-r--r--src/core/hle/kernel/k_address_arbiter.cpp28
-rw-r--r--src/core/hle/kernel/k_address_space_info.cpp (renamed from src/core/hle/kernel/memory/address_space_info.cpp)60
-rw-r--r--src/core/hle/kernel/k_address_space_info.h (renamed from src/core/hle/kernel/memory/address_space_info.h)15
-rw-r--r--src/core/hle/kernel/k_condition_variable.cpp20
-rw-r--r--src/core/hle/kernel/k_memory_block.h (renamed from src/core/hle/kernel/memory/memory_block.h)149
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.cpp (renamed from src/core/hle/kernel/memory/memory_block_manager.cpp)60
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.h (renamed from src/core/hle/kernel/memory/memory_block_manager.h)33
-rw-r--r--src/core/hle/kernel/k_memory_layout.h (renamed from src/core/hle/kernel/memory/memory_layout.h)34
-rw-r--r--src/core/hle/kernel/k_memory_manager.cpp (renamed from src/core/hle/kernel/memory/memory_manager.cpp)45
-rw-r--r--src/core/hle/kernel/k_memory_manager.h (renamed from src/core/hle/kernel/memory/memory_manager.h)49
-rw-r--r--src/core/hle/kernel/k_page_bitmap.h279
-rw-r--r--src/core/hle/kernel/k_page_heap.cpp (renamed from src/core/hle/kernel/memory/page_heap.cpp)23
-rw-r--r--src/core/hle/kernel/k_page_heap.h193
-rw-r--r--src/core/hle/kernel/k_page_linked_list.h (renamed from src/core/hle/kernel/memory/page_linked_list.h)14
-rw-r--r--src/core/hle/kernel/k_page_table.cpp (renamed from src/core/hle/kernel/memory/page_table.cpp)675
-rw-r--r--src/core/hle/kernel/k_page_table.h (renamed from src/core/hle/kernel/memory/page_table.h)98
-rw-r--r--src/core/hle/kernel/k_readable_event.cpp3
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp2
-rw-r--r--src/core/hle/kernel/k_scoped_resource_reservation.h67
-rw-r--r--src/core/hle/kernel/k_shared_memory.cpp65
-rw-r--r--src/core/hle/kernel/k_shared_memory.h (renamed from src/core/hle/kernel/shared_memory.h)24
-rw-r--r--src/core/hle/kernel/k_slab_heap.h (renamed from src/core/hle/kernel/memory/slab_heap.h)21
-rw-r--r--src/core/hle/kernel/k_spin_lock.cpp54
-rw-r--r--src/core/hle/kernel/k_spin_lock.h33
-rw-r--r--src/core/hle/kernel/k_synchronization_object.cpp8
-rw-r--r--src/core/hle/kernel/k_system_control.cpp (renamed from src/core/hle/kernel/memory/system_control.cpp)18
-rw-r--r--src/core/hle/kernel/k_system_control.h19
-rw-r--r--src/core/hle/kernel/k_thread.cpp38
-rw-r--r--src/core/hle/kernel/kernel.cpp114
-rw-r--r--src/core/hle/kernel/kernel.h44
-rw-r--r--src/core/hle/kernel/memory/page_heap.h370
-rw-r--r--src/core/hle/kernel/memory/system_control.h13
-rw-r--r--src/core/hle/kernel/memory_types.h (renamed from src/core/hle/kernel/memory/memory_types.h)4
-rw-r--r--src/core/hle/kernel/process.cpp89
-rw-r--r--src/core/hle/kernel/process.h11
-rw-r--r--src/core/hle/kernel/process_capability.cpp48
-rw-r--r--src/core/hle/kernel/process_capability.h16
-rw-r--r--src/core/hle/kernel/server_port.cpp4
-rw-r--r--src/core/hle/kernel/session.cpp11
-rw-r--r--src/core/hle/kernel/shared_memory.cpp57
-rw-r--r--src/core/hle/kernel/svc.cpp293
-rw-r--r--src/core/hle/kernel/svc_results.h21
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp6
-rw-r--r--src/core/hle/kernel/transfer_memory.h6
49 files changed, 1817 insertions, 1480 deletions
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index f8f005f15..0b6957e31 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -4,11 +4,11 @@
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/svc_results.h"
namespace Kernel {
@@ -21,7 +21,7 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
if (active_sessions >= max_sessions) {
- return ERR_MAX_CONNECTIONS_REACHED;
+ return ResultMaxConnectionsReached;
}
active_sessions++;
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index a2be1a8f6..e230f365a 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -3,11 +3,11 @@
// Refer to the license.txt file included.
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/svc_results.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -43,7 +43,7 @@ ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread,
Core::Timing::CoreTiming& core_timing) {
// Keep ServerSession alive until we're done working with it.
if (!parent->Server()) {
- return ERR_SESSION_CLOSED_BY_REMOTE;
+ return ResultSessionClosedByRemote;
}
// Signal the server session that new data is available
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
deleted file mode 100644
index 7d32a39f0..000000000
--- a/src/core/hle/kernel/errors.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/result.h"
-
-namespace Kernel {
-
-// Confirmed Switch kernel error codes
-
-constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
-constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
-constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59};
-constexpr ResultCode ERR_TERMINATION_REQUESTED{ErrorModule::Kernel, 59};
-constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
-constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
-constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103};
-constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104};
-constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
-constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
-constexpr ResultCode ERR_INVALID_CURRENT_MEMORY{ErrorModule::Kernel, 106};
-constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
-constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
-constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
-constexpr ResultCode ERR_INVALID_THREAD_PRIORITY{ErrorModule::Kernel, 112};
-constexpr ResultCode ERR_INVALID_HANDLE{ErrorModule::Kernel, 114};
-constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115};
-constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
-constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
-constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
-constexpr ResultCode ERR_CANCELLED{ErrorModule::Kernel, 118};
-constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
-constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
-constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
-constexpr ResultCode ERR_BUSY{ErrorModule::Kernel, 122};
-constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123};
-constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125};
-constexpr ResultCode ERR_RESERVED_VALUE{ErrorModule::Kernel, 126};
-constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132};
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 1a2fa9cd8..f96d34078 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -6,12 +6,12 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/svc_results.h"
namespace Kernel {
namespace {
@@ -33,7 +33,7 @@ HandleTable::~HandleTable() = default;
ResultCode HandleTable::SetSize(s32 handle_table_size) {
if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT);
- return ERR_OUT_OF_MEMORY;
+ return ResultOutOfMemory;
}
// Values less than or equal to zero indicate to use the maximum allowable
@@ -53,7 +53,7 @@ ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) {
const u16 slot = next_free_slot;
if (slot >= table_size) {
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
- return ERR_HANDLE_TABLE_FULL;
+ return ResultHandleTableFull;
}
next_free_slot = generations[slot];
@@ -76,7 +76,7 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
std::shared_ptr<Object> object = GetGeneric(handle);
if (object == nullptr) {
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
return Create(std::move(object));
}
@@ -84,7 +84,7 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
ResultCode HandleTable::Close(Handle handle) {
if (!IsValid(handle)) {
LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
const u16 slot = GetSlot(handle);
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 7ec62cf18..161d9f782 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -14,7 +14,6 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_readable_event.h"
@@ -26,6 +25,7 @@
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
#include "core/memory.h"
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp
index d0e90fd60..7018f56da 100644
--- a/src/core/hle/kernel/k_address_arbiter.cpp
+++ b/src/core/hle/kernel/k_address_arbiter.cpp
@@ -120,10 +120,10 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32
s32 user_value{};
if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) {
LOG_ERROR(Kernel, "Invalid current memory!");
- return Svc::ResultInvalidCurrentMemory;
+ return ResultInvalidCurrentMemory;
}
if (user_value != value) {
- return Svc::ResultInvalidState;
+ return ResultInvalidState;
}
auto it = thread_tree.nfind_light({addr, -1});
@@ -189,10 +189,10 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
if (!succeeded) {
LOG_ERROR(Kernel, "Invalid current memory!");
- return Svc::ResultInvalidCurrentMemory;
+ return ResultInvalidCurrentMemory;
}
if (user_value != value) {
- return Svc::ResultInvalidState;
+ return ResultInvalidState;
}
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
@@ -221,11 +221,11 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
- return Svc::ResultTerminationRequested;
+ return ResultTerminationRequested;
}
// Set the synced object.
- cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
+ cur_thread->SetSyncedObject(nullptr, ResultTimedOut);
// Read the value from userspace.
s32 user_value{};
@@ -238,19 +238,19 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
if (!succeeded) {
slp.CancelSleep();
- return Svc::ResultInvalidCurrentMemory;
+ return ResultInvalidCurrentMemory;
}
// Check that the value is less than the specified one.
if (user_value >= value) {
slp.CancelSleep();
- return Svc::ResultInvalidState;
+ return ResultInvalidState;
}
// Check that the timeout is non-zero.
if (timeout == 0) {
slp.CancelSleep();
- return Svc::ResultTimedOut;
+ return ResultTimedOut;
}
// Set the arbiter.
@@ -288,29 +288,29 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
- return Svc::ResultTerminationRequested;
+ return ResultTerminationRequested;
}
// Set the synced object.
- cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
+ cur_thread->SetSyncedObject(nullptr, ResultTimedOut);
// Read the value from userspace.
s32 user_value{};
if (!ReadFromUser(system, &user_value, addr)) {
slp.CancelSleep();
- return Svc::ResultInvalidCurrentMemory;
+ return ResultInvalidCurrentMemory;
}
// Check that the value is equal.
if (value != user_value) {
slp.CancelSleep();
- return Svc::ResultInvalidState;
+ return ResultInvalidState;
}
// Check that the timeout is non-zero.
if (timeout == 0) {
slp.CancelSleep();
- return Svc::ResultTimedOut;
+ return ResultTimedOut;
}
// Set the arbiter.
diff --git a/src/core/hle/kernel/memory/address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp
index 6cf43ba24..24944d15b 100644
--- a/src/core/hle/kernel/memory/address_space_info.cpp
+++ b/src/core/hle/kernel/k_address_space_info.cpp
@@ -2,15 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#include <array>
#include "common/assert.h"
-#include "core/hle/kernel/memory/address_space_info.h"
+#include "core/hle/kernel/k_address_space_info.h"
-namespace Kernel::Memory {
+namespace Kernel {
namespace {
@@ -28,20 +25,20 @@ enum : u64 {
};
// clang-format off
-constexpr std::array<AddressSpaceInfo, 13> AddressSpaceInfos{{
- { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = AddressSpaceInfo::Type::Is32Bit, },
- { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = AddressSpaceInfo::Type::Small64Bit, },
- { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Heap, },
- { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Alias, },
- { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Is32Bit, },
- { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = AddressSpaceInfo::Type::Small64Bit, },
- { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, },
- { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Alias, },
- { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Large64Bit, },
- { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Is32Bit },
- { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, },
- { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Alias, },
- { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = AddressSpaceInfo::Type::Stack, },
+constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
+ { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
+ { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
+ { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
+ { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
+ { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
+ { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
+ { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
+ { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
+ { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
+ { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
}};
// clang-format on
@@ -49,7 +46,8 @@ constexpr bool IsAllowedIndexForAddress(std::size_t index) {
return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid;
}
-using IndexArray = std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)>;
+using IndexArray =
+ std::array<std::size_t, static_cast<std::size_t>(KAddressSpaceInfo::Type::Count)>;
constexpr IndexArray AddressSpaceIndices32Bit{
0, 1, 0, 2, 0, 3,
@@ -63,23 +61,23 @@ constexpr IndexArray AddressSpaceIndices39Bit{
9, 8, 8, 10, 12, 11,
};
-constexpr bool IsAllowed32BitType(AddressSpaceInfo::Type type) {
- return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit &&
- type != AddressSpaceInfo::Type::Stack;
+constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) {
+ return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
+ type != KAddressSpaceInfo::Type::Stack;
}
-constexpr bool IsAllowed36BitType(AddressSpaceInfo::Type type) {
- return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit &&
- type != AddressSpaceInfo::Type::Stack;
+constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) {
+ return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
+ type != KAddressSpaceInfo::Type::Stack;
}
-constexpr bool IsAllowed39BitType(AddressSpaceInfo::Type type) {
- return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Small64Bit;
+constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) {
+ return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::MapLarge;
}
} // namespace
-u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) {
+u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) {
const std::size_t index{static_cast<std::size_t>(type)};
switch (width) {
case 32:
@@ -99,7 +97,7 @@ u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) {
return 0;
}
-std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) {
+std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) {
const std::size_t index{static_cast<std::size_t>(type)};
switch (width) {
case 32:
@@ -116,4 +114,4 @@ std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type)
return 0;
}
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/address_space_info.h b/src/core/hle/kernel/k_address_space_info.h
index a4e6e91e5..06f31c6d5 100644
--- a/src/core/hle/kernel/memory/address_space_info.h
+++ b/src/core/hle/kernel/k_address_space_info.h
@@ -2,20 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#pragma once
#include "common/common_types.h"
-namespace Kernel::Memory {
+namespace Kernel {
-struct AddressSpaceInfo final {
+struct KAddressSpaceInfo final {
enum class Type : u32 {
- Is32Bit = 0,
- Small64Bit = 1,
- Large64Bit = 2,
+ MapSmall = 0,
+ MapLarge = 1,
+ Map39Bit = 2,
Heap = 3,
Stack = 4,
Alias = 5,
@@ -31,4 +28,4 @@ struct AddressSpaceInfo final {
const Type type{};
};
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index f0ad8b390..170d8fa0d 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -92,10 +92,10 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
// Write the value to userspace.
if (!WriteToUser(system, addr, std::addressof(next_value))) {
if (next_owner_thread) {
- next_owner_thread->SetSyncedObject(nullptr, Svc::ResultInvalidCurrentMemory);
+ next_owner_thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory);
}
- return Svc::ResultInvalidCurrentMemory;
+ return ResultInvalidCurrentMemory;
}
}
@@ -114,20 +114,20 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
cur_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
// Check if the thread should terminate.
- R_UNLESS(!cur_thread->IsTerminationRequested(), Svc::ResultTerminationRequested);
+ R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested);
{
// Read the tag from userspace.
u32 test_tag{};
R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr),
- Svc::ResultInvalidCurrentMemory);
+ ResultInvalidCurrentMemory);
// If the tag isn't the handle (with wait mask), we're done.
R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS);
// Get the lock owner thread.
owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle);
- R_UNLESS(owner_thread, Svc::ResultInvalidHandle);
+ R_UNLESS(owner_thread, ResultInvalidHandle);
// Update the lock.
cur_thread->SetAddressKey(addr, value);
@@ -191,13 +191,13 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
thread_to_close = owner_thread.get();
} else {
// The lock was tagged with a thread that doesn't exist.
- thread->SetSyncedObject(nullptr, Svc::ResultInvalidState);
+ thread->SetSyncedObject(nullptr, ResultInvalidState);
thread->Wakeup();
}
}
} else {
// If the address wasn't accessible, note so.
- thread->SetSyncedObject(nullptr, Svc::ResultInvalidCurrentMemory);
+ thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory);
thread->Wakeup();
}
@@ -263,12 +263,12 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
// Set the synced object.
- cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
+ cur_thread->SetSyncedObject(nullptr, ResultTimedOut);
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
- return Svc::ResultTerminationRequested;
+ return ResultTerminationRequested;
}
// Update the value and process for the next owner.
@@ -302,7 +302,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
// Write the value to userspace.
if (!WriteToUser(system, addr, std::addressof(next_value))) {
slp.CancelSleep();
- return Svc::ResultInvalidCurrentMemory;
+ return ResultInvalidCurrentMemory;
}
}
diff --git a/src/core/hle/kernel/memory/memory_block.h b/src/core/hle/kernel/k_memory_block.h
index 83acece1e..c5b9c5e85 100644
--- a/src/core/hle/kernel/memory/memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -2,20 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#pragma once
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
-#include "core/hle/kernel/memory/memory_types.h"
+#include "core/hle/kernel/memory_types.h"
#include "core/hle/kernel/svc_types.h"
-namespace Kernel::Memory {
+namespace Kernel {
-enum class MemoryState : u32 {
+enum class KMemoryState : u32 {
None = 0,
Mask = 0xFF,
All = ~None,
@@ -97,31 +94,31 @@ enum class MemoryState : u32 {
FlagReferenceCounted | FlagCanDebug,
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted,
};
-DECLARE_ENUM_FLAG_OPERATORS(MemoryState);
-
-static_assert(static_cast<u32>(MemoryState::Free) == 0x00000000);
-static_assert(static_cast<u32>(MemoryState::Io) == 0x00002001);
-static_assert(static_cast<u32>(MemoryState::Static) == 0x00042002);
-static_assert(static_cast<u32>(MemoryState::Code) == 0x00DC7E03);
-static_assert(static_cast<u32>(MemoryState::CodeData) == 0x03FEBD04);
-static_assert(static_cast<u32>(MemoryState::Normal) == 0x037EBD05);
-static_assert(static_cast<u32>(MemoryState::Shared) == 0x00402006);
-static_assert(static_cast<u32>(MemoryState::AliasCode) == 0x00DD7E08);
-static_assert(static_cast<u32>(MemoryState::AliasCodeData) == 0x03FFBD09);
-static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A);
-static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B);
-static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C);
-static_assert(static_cast<u32>(MemoryState::Transferred) == 0x015C3C0D);
-static_assert(static_cast<u32>(MemoryState::SharedTransferred) == 0x005C380E);
-static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F);
-static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010);
-static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811);
-static_assert(static_cast<u32>(MemoryState::NonDeviceIpc) == 0x004C2812);
-static_assert(static_cast<u32>(MemoryState::Kernel) == 0x00002013);
-static_assert(static_cast<u32>(MemoryState::GeneratedCode) == 0x00402214);
-static_assert(static_cast<u32>(MemoryState::CodeOut) == 0x00402015);
-
-enum class MemoryPermission : u8 {
+DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
+
+static_assert(static_cast<u32>(KMemoryState::Free) == 0x00000000);
+static_assert(static_cast<u32>(KMemoryState::Io) == 0x00002001);
+static_assert(static_cast<u32>(KMemoryState::Static) == 0x00042002);
+static_assert(static_cast<u32>(KMemoryState::Code) == 0x00DC7E03);
+static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x03FEBD04);
+static_assert(static_cast<u32>(KMemoryState::Normal) == 0x037EBD05);
+static_assert(static_cast<u32>(KMemoryState::Shared) == 0x00402006);
+static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x00DD7E08);
+static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x03FFBD09);
+static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A);
+static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B);
+static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C);
+static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x015C3C0D);
+static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x005C380E);
+static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F);
+static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
+static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811);
+static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x004C2812);
+static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
+static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214);
+static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
+
+enum class KMemoryPermission : u8 {
None = 0,
Mask = static_cast<u8>(~None),
@@ -135,9 +132,9 @@ enum class MemoryPermission : u8 {
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
Svc::MemoryPermission::Execute),
};
-DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission);
+DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
-enum class MemoryAttribute : u8 {
+enum class KMemoryAttribute : u8 {
None = 0x00,
Mask = 0x7F,
All = Mask,
@@ -152,18 +149,18 @@ enum class MemoryAttribute : u8 {
LockedAndIpcLocked = Locked | IpcLocked,
DeviceSharedAndUncached = DeviceShared | Uncached
};
-DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute);
+DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute);
-static_assert((static_cast<u8>(MemoryAttribute::Mask) &
- static_cast<u8>(MemoryAttribute::DontCareMask)) == 0);
+static_assert((static_cast<u8>(KMemoryAttribute::Mask) &
+ static_cast<u8>(KMemoryAttribute::DontCareMask)) == 0);
-struct MemoryInfo {
+struct KMemoryInfo {
VAddr addr{};
std::size_t size{};
- MemoryState state{};
- MemoryPermission perm{};
- MemoryAttribute attribute{};
- MemoryPermission original_perm{};
+ KMemoryState state{};
+ KMemoryPermission perm{};
+ KMemoryAttribute attribute{};
+ KMemoryPermission original_perm{};
u16 ipc_lock_count{};
u16 device_use_count{};
@@ -171,9 +168,9 @@ struct MemoryInfo {
return {
addr,
size,
- static_cast<Svc::MemoryState>(state & MemoryState::Mask),
- static_cast<Svc::MemoryAttribute>(attribute & MemoryAttribute::Mask),
- static_cast<Svc::MemoryPermission>(perm & MemoryPermission::UserMask),
+ static_cast<Svc::MemoryState>(state & KMemoryState::Mask),
+ static_cast<Svc::MemoryAttribute>(attribute & KMemoryAttribute::Mask),
+ static_cast<Svc::MemoryPermission>(perm & KMemoryPermission::UserMask),
ipc_lock_count,
device_use_count,
};
@@ -196,21 +193,21 @@ struct MemoryInfo {
}
};
-class MemoryBlock final {
- friend class MemoryBlockManager;
+class KMemoryBlock final {
+ friend class KMemoryBlockManager;
private:
VAddr addr{};
std::size_t num_pages{};
- MemoryState state{MemoryState::None};
+ KMemoryState state{KMemoryState::None};
u16 ipc_lock_count{};
u16 device_use_count{};
- MemoryPermission perm{MemoryPermission::None};
- MemoryPermission original_perm{MemoryPermission::None};
- MemoryAttribute attribute{MemoryAttribute::None};
+ KMemoryPermission perm{KMemoryPermission::None};
+ KMemoryPermission original_perm{KMemoryPermission::None};
+ KMemoryAttribute attribute{KMemoryAttribute::None};
public:
- static constexpr int Compare(const MemoryBlock& lhs, const MemoryBlock& rhs) {
+ static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) {
if (lhs.GetAddress() < rhs.GetAddress()) {
return -1;
} else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
@@ -221,9 +218,9 @@ public:
}
public:
- constexpr MemoryBlock() = default;
- constexpr MemoryBlock(VAddr addr_, std::size_t num_pages_, MemoryState state_,
- MemoryPermission perm_, MemoryAttribute attribute_)
+ constexpr KMemoryBlock() = default;
+ constexpr KMemoryBlock(VAddr addr_, std::size_t num_pages_, KMemoryState state_,
+ KMemoryPermission perm_, KMemoryAttribute attribute_)
: addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {}
constexpr VAddr GetAddress() const {
@@ -246,40 +243,40 @@ public:
return GetEndAddress() - 1;
}
- constexpr MemoryInfo GetMemoryInfo() const {
+ constexpr KMemoryInfo GetMemoryInfo() const {
return {
GetAddress(), GetSize(), state, perm,
attribute, original_perm, ipc_lock_count, device_use_count,
};
}
- void ShareToDevice(MemoryPermission /*new_perm*/) {
- ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared ||
+ void ShareToDevice(KMemoryPermission /*new_perm*/) {
+ ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared ||
device_use_count == 0);
- attribute |= MemoryAttribute::DeviceShared;
+ attribute |= KMemoryAttribute::DeviceShared;
const u16 new_use_count{++device_use_count};
ASSERT(new_use_count > 0);
}
- void UnshareToDevice(MemoryPermission /*new_perm*/) {
- ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared);
+ void UnshareToDevice(KMemoryPermission /*new_perm*/) {
+ ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared);
const u16 prev_use_count{device_use_count--};
ASSERT(prev_use_count > 0);
if (prev_use_count == 1) {
- attribute &= ~MemoryAttribute::DeviceShared;
+ attribute &= ~KMemoryAttribute::DeviceShared;
}
}
private:
- constexpr bool HasProperties(MemoryState s, MemoryPermission p, MemoryAttribute a) const {
- constexpr MemoryAttribute AttributeIgnoreMask{MemoryAttribute::DontCareMask |
- MemoryAttribute::IpcLocked |
- MemoryAttribute::DeviceShared};
+ constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const {
+ constexpr KMemoryAttribute AttributeIgnoreMask{KMemoryAttribute::DontCareMask |
+ KMemoryAttribute::IpcLocked |
+ KMemoryAttribute::DeviceShared};
return state == s && perm == p &&
(attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask);
}
- constexpr bool HasSameProperties(const MemoryBlock& rhs) const {
+ constexpr bool HasSameProperties(const KMemoryBlock& rhs) const {
return state == rhs.state && perm == rhs.perm && original_perm == rhs.original_perm &&
attribute == rhs.attribute && ipc_lock_count == rhs.ipc_lock_count &&
device_use_count == rhs.device_use_count;
@@ -296,25 +293,25 @@ private:
num_pages += count;
}
- constexpr void Update(MemoryState new_state, MemoryPermission new_perm,
- MemoryAttribute new_attribute) {
- ASSERT(original_perm == MemoryPermission::None);
- ASSERT((attribute & MemoryAttribute::IpcLocked) == MemoryAttribute::None);
+ constexpr void Update(KMemoryState new_state, KMemoryPermission new_perm,
+ KMemoryAttribute new_attribute) {
+ ASSERT(original_perm == KMemoryPermission::None);
+ ASSERT((attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::None);
state = new_state;
perm = new_perm;
- attribute = static_cast<MemoryAttribute>(
+ attribute = static_cast<KMemoryAttribute>(
new_attribute |
- (attribute & (MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared)));
+ (attribute & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)));
}
- constexpr MemoryBlock Split(VAddr split_addr) {
+ constexpr KMemoryBlock Split(VAddr split_addr) {
ASSERT(GetAddress() < split_addr);
ASSERT(Contains(split_addr));
ASSERT(Common::IsAligned(split_addr, PageSize));
- MemoryBlock block;
+ KMemoryBlock block;
block.addr = addr;
block.num_pages = (split_addr - GetAddress()) / PageSize;
block.state = state;
@@ -330,6 +327,6 @@ private:
return block;
}
};
-static_assert(std::is_trivially_destructible<MemoryBlock>::value);
+static_assert(std::is_trivially_destructible<KMemoryBlock>::value);
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp
index 0732fa5a1..4a2d88008 100644
--- a/src/core/hle/kernel/memory/memory_block_manager.cpp
+++ b/src/core/hle/kernel/k_memory_block_manager.cpp
@@ -2,19 +2,19 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/hle/kernel/memory/memory_block_manager.h"
-#include "core/hle/kernel/memory/memory_types.h"
+#include "core/hle/kernel/k_memory_block_manager.h"
+#include "core/hle/kernel/memory_types.h"
-namespace Kernel::Memory {
+namespace Kernel {
-MemoryBlockManager::MemoryBlockManager(VAddr start_addr, VAddr end_addr)
+KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr)
: start_addr{start_addr}, end_addr{end_addr} {
const u64 num_pages{(end_addr - start_addr) / PageSize};
- memory_block_tree.emplace_back(start_addr, num_pages, MemoryState::Free, MemoryPermission::None,
- MemoryAttribute::None);
+ memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free,
+ KMemoryPermission::None, KMemoryAttribute::None);
}
-MemoryBlockManager::iterator MemoryBlockManager::FindIterator(VAddr addr) {
+KMemoryBlockManager::iterator KMemoryBlockManager::FindIterator(VAddr addr) {
auto node{memory_block_tree.begin()};
while (node != end()) {
const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()};
@@ -26,9 +26,9 @@ MemoryBlockManager::iterator MemoryBlockManager::FindIterator(VAddr addr) {
return end();
}
-VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_num_pages,
- std::size_t num_pages, std::size_t align, std::size_t offset,
- std::size_t guard_pages) {
+VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_num_pages,
+ std::size_t num_pages, std::size_t align,
+ std::size_t offset, std::size_t guard_pages) {
if (num_pages == 0) {
return {};
}
@@ -41,7 +41,7 @@ VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_nu
break;
}
- if (info.state != MemoryState::Free) {
+ if (info.state != KMemoryState::Free) {
continue;
}
@@ -63,17 +63,17 @@ VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_nu
return {};
}
-void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState prev_state,
- MemoryPermission prev_perm, MemoryAttribute prev_attribute,
- MemoryState state, MemoryPermission perm,
- MemoryAttribute attribute) {
+void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState prev_state,
+ KMemoryPermission prev_perm, KMemoryAttribute prev_attribute,
+ KMemoryState state, KMemoryPermission perm,
+ KMemoryAttribute attribute) {
const VAddr end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
- prev_attribute |= MemoryAttribute::IpcAndDeviceMapped;
+ prev_attribute |= KMemoryAttribute::IpcAndDeviceMapped;
while (node != memory_block_tree.end()) {
- MemoryBlock* block{&(*node)};
+ KMemoryBlock* block{&(*node)};
iterator next_node{std::next(node)};
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
@@ -106,13 +106,13 @@ void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState p
}
}
-void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState state,
- MemoryPermission perm, MemoryAttribute attribute) {
+void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState state,
+ KMemoryPermission perm, KMemoryAttribute attribute) {
const VAddr end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
while (node != memory_block_tree.end()) {
- MemoryBlock* block{&(*node)};
+ KMemoryBlock* block{&(*node)};
iterator next_node{std::next(node)};
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
@@ -141,13 +141,13 @@ void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState s
}
}
-void MemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
- MemoryPermission perm) {
+void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
+ KMemoryPermission perm) {
const VAddr end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
while (node != memory_block_tree.end()) {
- MemoryBlock* block{&(*node)};
+ KMemoryBlock* block{&(*node)};
iterator next_node{std::next(node)};
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
@@ -176,9 +176,9 @@ void MemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&
}
}
-void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) {
+void KMemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) {
const_iterator it{FindIterator(start)};
- MemoryInfo info{};
+ KMemoryInfo info{};
do {
info = it->GetMemoryInfo();
func(info);
@@ -186,8 +186,8 @@ void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& f
} while (info.addr + info.size - 1 < end - 1 && it != cend());
}
-void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
- MemoryBlock* block{&(*it)};
+void KMemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
+ KMemoryBlock* block{&(*it)};
auto EraseIt = [&](const iterator it_to_erase) {
if (next_it == it_to_erase) {
@@ -197,7 +197,7 @@ void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
};
if (it != memory_block_tree.begin()) {
- MemoryBlock* prev{&(*std::prev(it))};
+ KMemoryBlock* prev{&(*std::prev(it))};
if (block->HasSameProperties(*prev)) {
const iterator prev_it{std::prev(it)};
@@ -211,7 +211,7 @@ void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
}
if (it != cend()) {
- const MemoryBlock* const next{&(*std::next(it))};
+ const KMemoryBlock* const next{&(*std::next(it))};
if (block->HasSameProperties(*next)) {
block->Add(next->GetNumPages());
@@ -220,4 +220,4 @@ void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
}
}
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h
index f57d1bbcc..e11cc70c8 100644
--- a/src/core/hle/kernel/memory/memory_block_manager.h
+++ b/src/core/hle/kernel/k_memory_block_manager.h
@@ -8,18 +8,18 @@
#include <list>
#include "common/common_types.h"
-#include "core/hle/kernel/memory/memory_block.h"
+#include "core/hle/kernel/k_memory_block.h"
-namespace Kernel::Memory {
+namespace Kernel {
-class MemoryBlockManager final {
+class KMemoryBlockManager final {
public:
- using MemoryBlockTree = std::list<MemoryBlock>;
+ using MemoryBlockTree = std::list<KMemoryBlock>;
using iterator = MemoryBlockTree::iterator;
using const_iterator = MemoryBlockTree::const_iterator;
public:
- MemoryBlockManager(VAddr start_addr, VAddr end_addr);
+ KMemoryBlockManager(VAddr start_addr, VAddr end_addr);
iterator end() {
return memory_block_tree.end();
@@ -36,21 +36,22 @@ public:
VAddr FindFreeArea(VAddr region_start, std::size_t region_num_pages, std::size_t num_pages,
std::size_t align, std::size_t offset, std::size_t guard_pages);
- void Update(VAddr addr, std::size_t num_pages, MemoryState prev_state,
- MemoryPermission prev_perm, MemoryAttribute prev_attribute, MemoryState state,
- MemoryPermission perm, MemoryAttribute attribute);
+ void Update(VAddr addr, std::size_t num_pages, KMemoryState prev_state,
+ KMemoryPermission prev_perm, KMemoryAttribute prev_attribute, KMemoryState state,
+ KMemoryPermission perm, KMemoryAttribute attribute);
- void Update(VAddr addr, std::size_t num_pages, MemoryState state,
- MemoryPermission perm = MemoryPermission::None,
- MemoryAttribute attribute = MemoryAttribute::None);
+ void Update(VAddr addr, std::size_t num_pages, KMemoryState state,
+ KMemoryPermission perm = KMemoryPermission::None,
+ KMemoryAttribute attribute = KMemoryAttribute::None);
- using LockFunc = std::function<void(iterator, MemoryPermission)>;
- void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, MemoryPermission perm);
+ using LockFunc = std::function<void(iterator, KMemoryPermission)>;
+ void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
+ KMemoryPermission perm);
- using IterateFunc = std::function<void(const MemoryInfo&)>;
+ using IterateFunc = std::function<void(const KMemoryInfo&)>;
void IterateForRange(VAddr start, VAddr end, IterateFunc&& func);
- MemoryBlock& FindBlock(VAddr addr) {
+ KMemoryBlock& FindBlock(VAddr addr) {
return *FindIterator(addr);
}
@@ -63,4 +64,4 @@ private:
MemoryBlockTree memory_block_tree;
};
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/memory_layout.h b/src/core/hle/kernel/k_memory_layout.h
index c7c0b2f49..0821d2d8c 100644
--- a/src/core/hle/kernel/memory/memory_layout.h
+++ b/src/core/hle/kernel/k_memory_layout.h
@@ -7,7 +7,7 @@
#include "common/common_types.h"
#include "core/device_memory.h"
-namespace Kernel::Memory {
+namespace Kernel {
constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024;
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
@@ -27,8 +27,8 @@ constexpr bool IsKernelAddress(VAddr address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
}
-class MemoryRegion final {
- friend class MemoryLayout;
+class KMemoryRegion final {
+ friend class KMemoryLayout;
public:
constexpr PAddr StartAddress() const {
@@ -40,29 +40,29 @@ public:
}
private:
- constexpr MemoryRegion() = default;
- constexpr MemoryRegion(PAddr start_address, PAddr end_address)
+ constexpr KMemoryRegion() = default;
+ constexpr KMemoryRegion(PAddr start_address, PAddr end_address)
: start_address{start_address}, end_address{end_address} {}
const PAddr start_address{};
const PAddr end_address{};
};
-class MemoryLayout final {
+class KMemoryLayout final {
public:
- constexpr const MemoryRegion& Application() const {
+ constexpr const KMemoryRegion& Application() const {
return application;
}
- constexpr const MemoryRegion& Applet() const {
+ constexpr const KMemoryRegion& Applet() const {
return applet;
}
- constexpr const MemoryRegion& System() const {
+ constexpr const KMemoryRegion& System() const {
return system;
}
- static constexpr MemoryLayout GetDefaultLayout() {
+ static constexpr KMemoryLayout GetDefaultLayout() {
constexpr std::size_t application_size{0xcd500000};
constexpr std::size_t applet_size{0x1fb00000};
constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size};
@@ -76,15 +76,15 @@ public:
}
private:
- constexpr MemoryLayout(PAddr application_start_address, std::size_t application_size,
- PAddr applet_start_address, std::size_t applet_size,
- PAddr system_start_address, std::size_t system_size)
+ constexpr KMemoryLayout(PAddr application_start_address, std::size_t application_size,
+ PAddr applet_start_address, std::size_t applet_size,
+ PAddr system_start_address, std::size_t system_size)
: application{application_start_address, application_size},
applet{applet_start_address, applet_size}, system{system_start_address, system_size} {}
- const MemoryRegion application;
- const MemoryRegion applet;
- const MemoryRegion system;
+ const KMemoryRegion application;
+ const KMemoryRegion applet;
+ const KMemoryRegion system;
};
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp
index acf13585c..9027602bf 100644
--- a/src/core/hle/kernel/memory/memory_manager.cpp
+++ b/src/core/hle/kernel/k_memory_manager.cpp
@@ -8,20 +8,20 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/scope_exit.h"
-#include "core/hle/kernel/errors.h"
-#include "core/hle/kernel/memory/memory_manager.h"
-#include "core/hle/kernel/memory/page_linked_list.h"
+#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_page_linked_list.h"
+#include "core/hle/kernel/svc_results.h"
-namespace Kernel::Memory {
+namespace Kernel {
-std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) {
+std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) {
const auto size{end_address - start_address};
// Calculate metadata sizes
const auto ref_count_size{(size / PageSize) * sizeof(u16)};
const auto optimize_map_size{(Common::AlignUp((size / PageSize), 64) / 64) * sizeof(u64)};
const auto manager_size{Common::AlignUp(optimize_map_size + ref_count_size, PageSize)};
- const auto page_heap_size{PageHeap::CalculateMetadataOverheadSize(size)};
+ const auto page_heap_size{KPageHeap::CalculateManagementOverheadSize(size)};
const auto total_metadata_size{manager_size + page_heap_size};
ASSERT(manager_size <= total_metadata_size);
ASSERT(Common::IsAligned(total_metadata_size, PageSize));
@@ -41,29 +41,30 @@ std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u6
return total_metadata_size;
}
-void MemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) {
+void KMemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) {
ASSERT(pool < Pool::Count);
managers[static_cast<std::size_t>(pool)].Initialize(pool, start_address, end_address);
}
-VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align_pages, Pool pool,
- Direction dir) {
+VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size_t align_pages,
+ u32 option) {
// Early return if we're allocating no pages
if (num_pages == 0) {
return {};
}
// Lock the pool that we're allocating from
+ const auto [pool, dir] = DecodeOption(option);
const auto pool_index{static_cast<std::size_t>(pool)};
std::lock_guard lock{pool_locks[pool_index]};
// Choose a heap based on our page size request
- const s32 heap_index{PageHeap::GetAlignedBlockIndex(num_pages, align_pages)};
+ const s32 heap_index{KPageHeap::GetAlignedBlockIndex(num_pages, align_pages)};
// Loop, trying to iterate from each block
// TODO (bunnei): Support multiple managers
Impl& chosen_manager{managers[pool_index]};
- VAddr allocated_block{chosen_manager.AllocateBlock(heap_index)};
+ VAddr allocated_block{chosen_manager.AllocateBlock(heap_index, false)};
// If we failed to allocate, quit now
if (!allocated_block) {
@@ -71,7 +72,7 @@ VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align
}
// If we allocated more than we need, free some
- const auto allocated_pages{PageHeap::GetBlockNumPages(heap_index)};
+ const auto allocated_pages{KPageHeap::GetBlockNumPages(heap_index)};
if (allocated_pages > num_pages) {
chosen_manager.Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages);
}
@@ -79,8 +80,8 @@ VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align
return allocated_block;
}
-ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool,
- Direction dir) {
+ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
+ Direction dir) {
ASSERT(page_list.GetNumPages() == 0);
// Early return if we're allocating no pages
@@ -93,9 +94,9 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
std::lock_guard lock{pool_locks[pool_index]};
// Choose a heap based on our page size request
- const s32 heap_index{PageHeap::GetBlockIndex(num_pages)};
+ const s32 heap_index{KPageHeap::GetBlockIndex(num_pages)};
if (heap_index < 0) {
- return ERR_OUT_OF_MEMORY;
+ return ResultOutOfMemory;
}
// TODO (bunnei): Support multiple managers
@@ -112,11 +113,11 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
// Keep allocating until we've allocated all our pages
for (s32 index{heap_index}; index >= 0 && num_pages > 0; index--) {
- const auto pages_per_alloc{PageHeap::GetBlockNumPages(index)};
+ const auto pages_per_alloc{KPageHeap::GetBlockNumPages(index)};
while (num_pages >= pages_per_alloc) {
// Allocate a block
- VAddr allocated_block{chosen_manager.AllocateBlock(index)};
+ VAddr allocated_block{chosen_manager.AllocateBlock(index, false)};
if (!allocated_block) {
break;
}
@@ -140,7 +141,7 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
// Only succeed if we allocated as many pages as we wanted
if (num_pages) {
- return ERR_OUT_OF_MEMORY;
+ return ResultOutOfMemory;
}
// We succeeded!
@@ -148,8 +149,8 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
return RESULT_SUCCESS;
}
-ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool,
- Direction dir) {
+ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
+ Direction dir) {
// Early return if we're freeing no pages
if (!num_pages) {
return RESULT_SUCCESS;
@@ -172,4 +173,4 @@ ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages,
return RESULT_SUCCESS;
}
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/memory_manager.h b/src/core/hle/kernel/k_memory_manager.h
index 3cf444857..ae9f683b8 100644
--- a/src/core/hle/kernel/memory/memory_manager.h
+++ b/src/core/hle/kernel/k_memory_manager.h
@@ -6,16 +6,18 @@
#include <array>
#include <mutex>
+#include <tuple>
+#include "common/common_funcs.h"
#include "common/common_types.h"
-#include "core/hle/kernel/memory/page_heap.h"
+#include "core/hle/kernel/k_page_heap.h"
#include "core/hle/result.h"
-namespace Kernel::Memory {
+namespace Kernel {
-class PageLinkedList;
+class KPageLinkedList;
-class MemoryManager final : NonCopyable {
+class KMemoryManager final : NonCopyable {
public:
enum class Pool : u32 {
Application = 0,
@@ -37,29 +39,50 @@ public:
Mask = (0xF << Shift),
};
- MemoryManager() = default;
+ KMemoryManager() = default;
constexpr std::size_t GetSize(Pool pool) const {
return managers[static_cast<std::size_t>(pool)].GetSize();
}
void InitializeManager(Pool pool, u64 start_address, u64 end_address);
- VAddr AllocateContinuous(std::size_t num_pages, std::size_t align_pages, Pool pool,
- Direction dir = Direction::FromFront);
- ResultCode Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool,
+
+ VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
+ ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir = Direction::FromFront);
- ResultCode Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool,
+ ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir = Direction::FromFront);
static constexpr std::size_t MaxManagerCount = 10;
+public:
+ static constexpr u32 EncodeOption(Pool pool, Direction dir) {
+ return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
+ (static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
+ }
+
+ static constexpr Pool GetPool(u32 option) {
+ return static_cast<Pool>((static_cast<u32>(option) & static_cast<u32>(Pool::Mask)) >>
+ static_cast<u32>(Pool::Shift));
+ }
+
+ static constexpr Direction GetDirection(u32 option) {
+ return static_cast<Direction>(
+ (static_cast<u32>(option) & static_cast<u32>(Direction::Mask)) >>
+ static_cast<u32>(Direction::Shift));
+ }
+
+ static constexpr std::tuple<Pool, Direction> DecodeOption(u32 option) {
+ return std::make_tuple(GetPool(option), GetDirection(option));
+ }
+
private:
class Impl final : NonCopyable {
private:
using RefCount = u16;
private:
- PageHeap heap;
+ KPageHeap heap;
Pool pool{};
public:
@@ -67,8 +90,8 @@ private:
std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address);
- VAddr AllocateBlock(s32 index) {
- return heap.AllocateBlock(index);
+ VAddr AllocateBlock(s32 index, bool random) {
+ return heap.AllocateBlock(index, random);
}
void Free(VAddr addr, std::size_t num_pages) {
@@ -93,4 +116,4 @@ private:
std::array<Impl, MaxManagerCount> managers;
};
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_page_bitmap.h b/src/core/hle/kernel/k_page_bitmap.h
new file mode 100644
index 000000000..c75d667c9
--- /dev/null
+++ b/src/core/hle/kernel/k_page_bitmap.h
@@ -0,0 +1,279 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <bit>
+
+#include "common/alignment.h"
+#include "common/assert.h"
+#include "common/bit_util.h"
+#include "common/common_types.h"
+#include "common/tiny_mt.h"
+#include "core/hle/kernel/k_system_control.h"
+
+namespace Kernel {
+
+class KPageBitmap {
+private:
+ class RandomBitGenerator {
+ private:
+ Common::TinyMT rng{};
+ u32 entropy{};
+ u32 bits_available{};
+
+ private:
+ void RefreshEntropy() {
+ entropy = rng.GenerateRandomU32();
+ bits_available = static_cast<u32>(Common::BitSize<decltype(entropy)>());
+ }
+
+ bool GenerateRandomBit() {
+ if (bits_available == 0) {
+ this->RefreshEntropy();
+ }
+
+ const bool rnd_bit = (entropy & 1) != 0;
+ entropy >>= 1;
+ --bits_available;
+ return rnd_bit;
+ }
+
+ public:
+ RandomBitGenerator() {
+ rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
+ }
+
+ std::size_t SelectRandomBit(u64 bitmap) {
+ u64 selected = 0;
+
+ u64 cur_num_bits = Common::BitSize<decltype(bitmap)>() / 2;
+ u64 cur_mask = (1ULL << cur_num_bits) - 1;
+
+ while (cur_num_bits) {
+ const u64 low = (bitmap >> 0) & cur_mask;
+ const u64 high = (bitmap >> cur_num_bits) & cur_mask;
+
+ bool choose_low;
+ if (high == 0) {
+ // If only low val is set, choose low.
+ choose_low = true;
+ } else if (low == 0) {
+ // If only high val is set, choose high.
+ choose_low = false;
+ } else {
+ // If both are set, choose random.
+ choose_low = this->GenerateRandomBit();
+ }
+
+ // If we chose low, proceed with low.
+ if (choose_low) {
+ bitmap = low;
+ selected += 0;
+ } else {
+ bitmap = high;
+ selected += cur_num_bits;
+ }
+
+ // Proceed.
+ cur_num_bits /= 2;
+ cur_mask >>= cur_num_bits;
+ }
+
+ return selected;
+ }
+ };
+
+public:
+ static constexpr std::size_t MaxDepth = 4;
+
+private:
+ std::array<u64*, MaxDepth> bit_storages{};
+ RandomBitGenerator rng{};
+ std::size_t num_bits{};
+ std::size_t used_depths{};
+
+public:
+ KPageBitmap() = default;
+
+ constexpr std::size_t GetNumBits() const {
+ return num_bits;
+ }
+ constexpr s32 GetHighestDepthIndex() const {
+ return static_cast<s32>(used_depths) - 1;
+ }
+
+ u64* Initialize(u64* storage, std::size_t size) {
+ // Initially, everything is un-set.
+ num_bits = 0;
+
+ // Calculate the needed bitmap depth.
+ used_depths = static_cast<std::size_t>(GetRequiredDepth(size));
+ ASSERT(used_depths <= MaxDepth);
+
+ // Set the bitmap pointers.
+ for (s32 depth = this->GetHighestDepthIndex(); depth >= 0; depth--) {
+ bit_storages[depth] = storage;
+ size = Common::AlignUp(size, Common::BitSize<u64>()) / Common::BitSize<u64>();
+ storage += size;
+ }
+
+ return storage;
+ }
+
+ s64 FindFreeBlock(bool random) {
+ uintptr_t offset = 0;
+ s32 depth = 0;
+
+ if (random) {
+ do {
+ const u64 v = bit_storages[depth][offset];
+ if (v == 0) {
+ // If depth is bigger than zero, then a previous level indicated a block was
+ // free.
+ ASSERT(depth == 0);
+ return -1;
+ }
+ offset = offset * Common::BitSize<u64>() + rng.SelectRandomBit(v);
+ ++depth;
+ } while (depth < static_cast<s32>(used_depths));
+ } else {
+ do {
+ const u64 v = bit_storages[depth][offset];
+ if (v == 0) {
+ // If depth is bigger than zero, then a previous level indicated a block was
+ // free.
+ ASSERT(depth == 0);
+ return -1;
+ }
+ offset = offset * Common::BitSize<u64>() + std::countr_zero(v);
+ ++depth;
+ } while (depth < static_cast<s32>(used_depths));
+ }
+
+ return static_cast<s64>(offset);
+ }
+
+ void SetBit(std::size_t offset) {
+ this->SetBit(this->GetHighestDepthIndex(), offset);
+ num_bits++;
+ }
+
+ void ClearBit(std::size_t offset) {
+ this->ClearBit(this->GetHighestDepthIndex(), offset);
+ num_bits--;
+ }
+
+ bool ClearRange(std::size_t offset, std::size_t count) {
+ s32 depth = this->GetHighestDepthIndex();
+ u64* bits = bit_storages[depth];
+ std::size_t bit_ind = offset / Common::BitSize<u64>();
+ if (count < Common::BitSize<u64>()) {
+ const std::size_t shift = offset % Common::BitSize<u64>();
+ ASSERT(shift + count <= Common::BitSize<u64>());
+ // Check that all the bits are set.
+ const u64 mask = ((u64(1) << count) - 1) << shift;
+ u64 v = bits[bit_ind];
+ if ((v & mask) != mask) {
+ return false;
+ }
+
+ // Clear the bits.
+ v &= ~mask;
+ bits[bit_ind] = v;
+ if (v == 0) {
+ this->ClearBit(depth - 1, bit_ind);
+ }
+ } else {
+ ASSERT(offset % Common::BitSize<u64>() == 0);
+ ASSERT(count % Common::BitSize<u64>() == 0);
+ // Check that all the bits are set.
+ std::size_t remaining = count;
+ std::size_t i = 0;
+ do {
+ if (bits[bit_ind + i++] != ~u64(0)) {
+ return false;
+ }
+ remaining -= Common::BitSize<u64>();
+ } while (remaining > 0);
+
+ // Clear the bits.
+ remaining = count;
+ i = 0;
+ do {
+ bits[bit_ind + i] = 0;
+ this->ClearBit(depth - 1, bit_ind + i);
+ i++;
+ remaining -= Common::BitSize<u64>();
+ } while (remaining > 0);
+ }
+
+ num_bits -= count;
+ return true;
+ }
+
+private:
+ void SetBit(s32 depth, std::size_t offset) {
+ while (depth >= 0) {
+ std::size_t ind = offset / Common::BitSize<u64>();
+ std::size_t which = offset % Common::BitSize<u64>();
+ const u64 mask = u64(1) << which;
+
+ u64* bit = std::addressof(bit_storages[depth][ind]);
+ u64 v = *bit;
+ ASSERT((v & mask) == 0);
+ *bit = v | mask;
+ if (v) {
+ break;
+ }
+ offset = ind;
+ depth--;
+ }
+ }
+
+ void ClearBit(s32 depth, std::size_t offset) {
+ while (depth >= 0) {
+ std::size_t ind = offset / Common::BitSize<u64>();
+ std::size_t which = offset % Common::BitSize<u64>();
+ const u64 mask = u64(1) << which;
+
+ u64* bit = std::addressof(bit_storages[depth][ind]);
+ u64 v = *bit;
+ ASSERT((v & mask) != 0);
+ v &= ~mask;
+ *bit = v;
+ if (v) {
+ break;
+ }
+ offset = ind;
+ depth--;
+ }
+ }
+
+private:
+ static constexpr s32 GetRequiredDepth(std::size_t region_size) {
+ s32 depth = 0;
+ while (true) {
+ region_size /= Common::BitSize<u64>();
+ depth++;
+ if (region_size == 0) {
+ return depth;
+ }
+ }
+ }
+
+public:
+ static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
+ std::size_t overhead_bits = 0;
+ for (s32 depth = GetRequiredDepth(region_size) - 1; depth >= 0; depth--) {
+ region_size =
+ Common::AlignUp(region_size, Common::BitSize<u64>()) / Common::BitSize<u64>();
+ overhead_bits += region_size;
+ }
+ return overhead_bits * sizeof(u64);
+ }
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/page_heap.cpp b/src/core/hle/kernel/k_page_heap.cpp
index 0ab1f7205..07e062922 100644
--- a/src/core/hle/kernel/memory/page_heap.cpp
+++ b/src/core/hle/kernel/k_page_heap.cpp
@@ -2,16 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#include "core/core.h"
-#include "core/hle/kernel/memory/page_heap.h"
+#include "core/hle/kernel/k_page_heap.h"
#include "core/memory.h"
-namespace Kernel::Memory {
+namespace Kernel {
-void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) {
+void KPageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) {
// Check our assumptions
ASSERT(Common::IsAligned((address), PageSize));
ASSERT(Common::IsAligned(size, PageSize));
@@ -32,11 +29,11 @@ void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_
}
}
-VAddr PageHeap::AllocateBlock(s32 index) {
+VAddr KPageHeap::AllocateBlock(s32 index, bool random) {
const std::size_t needed_size{blocks[index].GetSize()};
for (s32 i{index}; i < static_cast<s32>(MemoryBlockPageShifts.size()); i++) {
- if (const VAddr addr{blocks[i].PopBlock()}; addr) {
+ if (const VAddr addr{blocks[i].PopBlock(random)}; addr) {
if (const std::size_t allocated_size{blocks[i].GetSize()};
allocated_size > needed_size) {
Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
@@ -48,13 +45,13 @@ VAddr PageHeap::AllocateBlock(s32 index) {
return 0;
}
-void PageHeap::FreeBlock(VAddr block, s32 index) {
+void KPageHeap::FreeBlock(VAddr block, s32 index) {
do {
block = blocks[index++].PushBlock(block);
} while (block != 0);
}
-void PageHeap::Free(VAddr addr, std::size_t num_pages) {
+void KPageHeap::Free(VAddr addr, std::size_t num_pages) {
// Freeing no pages is a no-op
if (num_pages == 0) {
return;
@@ -104,16 +101,16 @@ void PageHeap::Free(VAddr addr, std::size_t num_pages) {
}
}
-std::size_t PageHeap::CalculateMetadataOverheadSize(std::size_t region_size) {
+std::size_t KPageHeap::CalculateManagementOverheadSize(std::size_t region_size) {
std::size_t overhead_size = 0;
for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) {
const std::size_t cur_block_shift{MemoryBlockPageShifts[i]};
const std::size_t next_block_shift{
(i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0};
- overhead_size += PageHeap::Block::CalculateMetadataOverheadSize(
+ overhead_size += KPageHeap::Block::CalculateManagementOverheadSize(
region_size, cur_block_shift, next_block_shift);
}
return Common::AlignUp(overhead_size, PageSize);
}
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_page_heap.h b/src/core/hle/kernel/k_page_heap.h
new file mode 100644
index 000000000..de5d6a189
--- /dev/null
+++ b/src/core/hle/kernel/k_page_heap.h
@@ -0,0 +1,193 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <bit>
+#include <vector>
+
+#include "common/alignment.h"
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "core/hle/kernel/k_page_bitmap.h"
+#include "core/hle/kernel/memory_types.h"
+
+namespace Kernel {
+
+class KPageHeap final : NonCopyable {
+public:
+ static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) {
+ const auto target_pages{std::max(num_pages, align_pages)};
+ for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) {
+ if (target_pages <=
+ (static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
+ return static_cast<s32>(i);
+ }
+ }
+ return -1;
+ }
+
+ static constexpr s32 GetBlockIndex(std::size_t num_pages) {
+ for (s32 i{static_cast<s32>(NumMemoryBlockPageShifts) - 1}; i >= 0; i--) {
+ if (num_pages >= (static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ static constexpr std::size_t GetBlockSize(std::size_t index) {
+ return static_cast<std::size_t>(1) << MemoryBlockPageShifts[index];
+ }
+
+ static constexpr std::size_t GetBlockNumPages(std::size_t index) {
+ return GetBlockSize(index) / PageSize;
+ }
+
+private:
+ static constexpr std::size_t NumMemoryBlockPageShifts{7};
+ static constexpr std::array<std::size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
+ 0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E,
+ };
+
+ class Block final : NonCopyable {
+ private:
+ KPageBitmap bitmap;
+ VAddr heap_address{};
+ uintptr_t end_offset{};
+ std::size_t block_shift{};
+ std::size_t next_block_shift{};
+
+ public:
+ Block() = default;
+
+ constexpr std::size_t GetShift() const {
+ return block_shift;
+ }
+ constexpr std::size_t GetNextShift() const {
+ return next_block_shift;
+ }
+ constexpr std::size_t GetSize() const {
+ return static_cast<std::size_t>(1) << GetShift();
+ }
+ constexpr std::size_t GetNumPages() const {
+ return GetSize() / PageSize;
+ }
+ constexpr std::size_t GetNumFreeBlocks() const {
+ return bitmap.GetNumBits();
+ }
+ constexpr std::size_t GetNumFreePages() const {
+ return GetNumFreeBlocks() * GetNumPages();
+ }
+
+ u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs,
+ u64* bit_storage) {
+ // Set shifts
+ block_shift = bs;
+ next_block_shift = nbs;
+
+ // Align up the address
+ VAddr end{addr + size};
+ const auto align{(next_block_shift != 0) ? (1ULL << next_block_shift)
+ : (1ULL << block_shift)};
+ addr = Common::AlignDown((addr), align);
+ end = Common::AlignUp((end), align);
+
+ heap_address = addr;
+ end_offset = (end - addr) / (1ULL << block_shift);
+ return bitmap.Initialize(bit_storage, end_offset);
+ }
+
+ VAddr PushBlock(VAddr address) {
+ // Set the bit for the free block
+ std::size_t offset{(address - heap_address) >> GetShift()};
+ bitmap.SetBit(offset);
+
+ // If we have a next shift, try to clear the blocks below and return the address
+ if (GetNextShift()) {
+ const auto diff{1ULL << (GetNextShift() - GetShift())};
+ offset = Common::AlignDown(offset, diff);
+ if (bitmap.ClearRange(offset, diff)) {
+ return heap_address + (offset << GetShift());
+ }
+ }
+
+ // We couldn't coalesce, or we're already as big as possible
+ return 0;
+ }
+
+ VAddr PopBlock(bool random) {
+ // Find a free block
+ const s64 soffset{bitmap.FindFreeBlock(random)};
+ if (soffset < 0) {
+ return 0;
+ }
+ const auto offset{static_cast<std::size_t>(soffset)};
+
+ // Update our tracking and return it
+ bitmap.ClearBit(offset);
+ return heap_address + (offset << GetShift());
+ }
+
+ public:
+ static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size,
+ std::size_t cur_block_shift,
+ std::size_t next_block_shift) {
+ const auto cur_block_size{(1ULL << cur_block_shift)};
+ const auto next_block_size{(1ULL << next_block_shift)};
+ const auto align{(next_block_shift != 0) ? next_block_size : cur_block_size};
+ return KPageBitmap::CalculateManagementOverheadSize(
+ (align * 2 + Common::AlignUp(region_size, align)) / cur_block_size);
+ }
+ };
+
+public:
+ KPageHeap() = default;
+
+ constexpr VAddr GetAddress() const {
+ return heap_address;
+ }
+ constexpr std::size_t GetSize() const {
+ return heap_size;
+ }
+ constexpr VAddr GetEndAddress() const {
+ return GetAddress() + GetSize();
+ }
+ constexpr std::size_t GetPageOffset(VAddr block) const {
+ return (block - GetAddress()) / PageSize;
+ }
+
+ void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size);
+ VAddr AllocateBlock(s32 index, bool random);
+ void Free(VAddr addr, std::size_t num_pages);
+
+ void UpdateUsedSize() {
+ used_size = heap_size - (GetNumFreePages() * PageSize);
+ }
+
+ static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
+
+private:
+ constexpr std::size_t GetNumFreePages() const {
+ std::size_t num_free{};
+
+ for (const auto& block : blocks) {
+ num_free += block.GetNumFreePages();
+ }
+
+ return num_free;
+ }
+
+ void FreeBlock(VAddr block, s32 index);
+
+ VAddr heap_address{};
+ std::size_t heap_size{};
+ std::size_t used_size{};
+ std::array<Block, NumMemoryBlockPageShifts> blocks{};
+ std::vector<u64> metadata;
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h
index 45dc13eaf..64024d01f 100644
--- a/src/core/hle/kernel/memory/page_linked_list.h
+++ b/src/core/hle/kernel/k_page_linked_list.h
@@ -8,12 +8,12 @@
#include "common/assert.h"
#include "common/common_types.h"
-#include "core/hle/kernel/memory/memory_types.h"
+#include "core/hle/kernel/memory_types.h"
#include "core/hle/result.h"
-namespace Kernel::Memory {
+namespace Kernel {
-class PageLinkedList final {
+class KPageLinkedList final {
public:
class Node final {
public:
@@ -33,8 +33,8 @@ public:
};
public:
- PageLinkedList() = default;
- PageLinkedList(u64 address, u64 num_pages) {
+ KPageLinkedList() = default;
+ KPageLinkedList(u64 address, u64 num_pages) {
ASSERT(AddBlock(address, num_pages).IsSuccess());
}
@@ -54,7 +54,7 @@ public:
return num_pages;
}
- bool IsEqual(PageLinkedList& other) const {
+ bool IsEqual(KPageLinkedList& other) const {
auto this_node = nodes.begin();
auto other_node = other.nodes.begin();
while (this_node != nodes.end() && other_node != other.nodes.end()) {
@@ -89,4 +89,4 @@ private:
std::list<Node> nodes;
};
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 7de91c768..d09d5ce48 100644
--- a/src/core/hle/kernel/memory/page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -6,19 +6,20 @@
#include "common/assert.h"
#include "common/scope_exit.h"
#include "core/core.h"
-#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/k_address_space_info.h"
+#include "core/hle/kernel/k_memory_block.h"
+#include "core/hle/kernel/k_memory_block_manager.h"
+#include "core/hle/kernel/k_page_linked_list.h"
+#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory/address_space_info.h"
-#include "core/hle/kernel/memory/memory_block.h"
-#include "core/hle/kernel/memory/memory_block_manager.h"
-#include "core/hle/kernel/memory/page_linked_list.h"
-#include "core/hle/kernel/memory/page_table.h"
-#include "core/hle/kernel/memory/system_control.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/svc_results.h"
#include "core/memory.h"
-namespace Kernel::Memory {
+namespace Kernel {
namespace {
@@ -37,14 +38,14 @@ constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceT
}
}
-constexpr u64 GetAddressInRange(const MemoryInfo& info, VAddr addr) {
+constexpr u64 GetAddressInRange(const KMemoryInfo& info, VAddr addr) {
if (info.GetAddress() < addr) {
return addr;
}
return info.GetAddress();
}
-constexpr std::size_t GetSizeInRange(const MemoryInfo& info, VAddr start, VAddr end) {
+constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr end) {
std::size_t size{info.GetSize()};
if (info.GetAddress() < start) {
size -= start - info.GetAddress();
@@ -57,25 +58,25 @@ constexpr std::size_t GetSizeInRange(const MemoryInfo& info, VAddr start, VAddr
} // namespace
-PageTable::PageTable(Core::System& system) : system{system} {}
+KPageTable::KPageTable(Core::System& system) : system{system} {}
-ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
- bool enable_aslr, VAddr code_addr, std::size_t code_size,
- Memory::MemoryManager::Pool pool) {
+ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
+ bool enable_aslr, VAddr code_addr,
+ std::size_t code_size, KMemoryManager::Pool pool) {
- const auto GetSpaceStart = [this](AddressSpaceInfo::Type type) {
- return AddressSpaceInfo::GetAddressSpaceStart(address_space_width, type);
+ const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) {
+ return KAddressSpaceInfo::GetAddressSpaceStart(address_space_width, type);
};
- const auto GetSpaceSize = [this](AddressSpaceInfo::Type type) {
- return AddressSpaceInfo::GetAddressSpaceSize(address_space_width, type);
+ const auto GetSpaceSize = [this](KAddressSpaceInfo::Type type) {
+ return KAddressSpaceInfo::GetAddressSpaceSize(address_space_width, type);
};
// Set our width and heap/alias sizes
address_space_width = GetAddressSpaceWidthFromType(as_type);
const VAddr start = 0;
const VAddr end{1ULL << address_space_width};
- std::size_t alias_region_size{GetSpaceSize(AddressSpaceInfo::Type::Alias)};
- std::size_t heap_region_size{GetSpaceSize(AddressSpaceInfo::Type::Heap)};
+ std::size_t alias_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Alias)};
+ std::size_t heap_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Heap)};
ASSERT(start <= code_addr);
ASSERT(code_addr < code_addr + code_size);
@@ -95,12 +96,12 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t
std::size_t kernel_map_region_size{};
if (address_space_width == 39) {
- alias_region_size = GetSpaceSize(AddressSpaceInfo::Type::Alias);
- heap_region_size = GetSpaceSize(AddressSpaceInfo::Type::Heap);
- stack_region_size = GetSpaceSize(AddressSpaceInfo::Type::Stack);
- kernel_map_region_size = GetSpaceSize(AddressSpaceInfo::Type::Is32Bit);
- code_region_start = GetSpaceStart(AddressSpaceInfo::Type::Large64Bit);
- code_region_end = code_region_start + GetSpaceSize(AddressSpaceInfo::Type::Large64Bit);
+ alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Alias);
+ heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap);
+ stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack);
+ kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
+ code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit);
+ code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit);
alias_code_region_start = code_region_start;
alias_code_region_end = code_region_end;
process_code_start = Common::AlignDown(code_addr, RegionAlignment);
@@ -108,12 +109,12 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t
} else {
stack_region_size = 0;
kernel_map_region_size = 0;
- code_region_start = GetSpaceStart(AddressSpaceInfo::Type::Is32Bit);
- code_region_end = code_region_start + GetSpaceSize(AddressSpaceInfo::Type::Is32Bit);
+ code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::MapSmall);
+ code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
stack_region_start = code_region_start;
alias_code_region_start = code_region_start;
- alias_code_region_end = GetSpaceStart(AddressSpaceInfo::Type::Small64Bit) +
- GetSpaceSize(AddressSpaceInfo::Type::Small64Bit);
+ alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type::MapLarge) +
+ GetSpaceSize(KAddressSpaceInfo::Type::MapLarge);
stack_region_end = code_region_end;
kernel_map_region_start = code_region_start;
kernel_map_region_end = code_region_end;
@@ -141,7 +142,7 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t
(alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)};
if (alloc_size < needed_size) {
UNREACHABLE();
- return ERR_OUT_OF_MEMORY;
+ return ResultOutOfMemory;
}
const std::size_t remaining_size{alloc_size - needed_size};
@@ -149,13 +150,13 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t
// Determine random placements for each region
std::size_t alias_rnd{}, heap_rnd{}, stack_rnd{}, kmap_rnd{};
if (enable_aslr) {
- alias_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
+ alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
- heap_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
+ heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
- stack_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
+ stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
- kmap_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
+ kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
}
@@ -270,21 +271,21 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t
return InitializeMemoryLayout(start, end);
}
-ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, MemoryState state,
- MemoryPermission perm) {
+ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state,
+ KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
const u64 size{num_pages * PageSize};
if (!CanContain(addr, size, state)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (IsRegionMapped(addr, size)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
- PageLinkedList page_linked_list;
+ KPageLinkedList page_linked_list;
CASCADE_CODE(
system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool));
CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup));
@@ -294,44 +295,44 @@ ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, MemorySt
return RESULT_SUCCESS;
}
-ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
+ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
const std::size_t num_pages{size / PageSize};
- MemoryState state{};
- MemoryPermission perm{};
- CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, MemoryState::All,
- MemoryState::Normal, MemoryPermission::Mask,
- MemoryPermission::ReadAndWrite, MemoryAttribute::Mask,
- MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped));
+ KMemoryState state{};
+ KMemoryPermission perm{};
+ CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All,
+ KMemoryState::Normal, KMemoryPermission::Mask,
+ KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask,
+ KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
if (IsRegionMapped(dst_addr, size)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
- PageLinkedList page_linked_list;
+ KPageLinkedList page_linked_list;
AddRegionToPages(src_addr, num_pages, page_linked_list);
{
auto block_guard = detail::ScopeExit(
[&] { Operate(src_addr, num_pages, perm, OperationType::ChangePermissions); });
- CASCADE_CODE(
- Operate(src_addr, num_pages, MemoryPermission::None, OperationType::ChangePermissions));
- CASCADE_CODE(MapPages(dst_addr, page_linked_list, MemoryPermission::None));
+ CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None,
+ OperationType::ChangePermissions));
+ CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::None));
block_guard.Cancel();
}
- block_manager->Update(src_addr, num_pages, state, MemoryPermission::None,
- MemoryAttribute::Locked);
- block_manager->Update(dst_addr, num_pages, MemoryState::AliasCode);
+ block_manager->Update(src_addr, num_pages, state, KMemoryPermission::None,
+ KMemoryAttribute::Locked);
+ block_manager->Update(dst_addr, num_pages, KMemoryState::AliasCode);
return RESULT_SUCCESS;
}
-ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
+ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
if (!size) {
@@ -340,34 +341,35 @@ ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std
const std::size_t num_pages{size / PageSize};
- CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, MemoryState::All,
- MemoryState::Normal, MemoryPermission::None,
- MemoryPermission::None, MemoryAttribute::Mask,
- MemoryAttribute::Locked, MemoryAttribute::IpcAndDeviceMapped));
+ CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, KMemoryState::All,
+ KMemoryState::Normal, KMemoryPermission::None,
+ KMemoryPermission::None, KMemoryAttribute::Mask,
+ KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
- MemoryState state{};
+ KMemoryState state{};
CASCADE_CODE(CheckMemoryState(
- &state, nullptr, nullptr, dst_addr, PageSize, MemoryState::FlagCanCodeAlias,
- MemoryState::FlagCanCodeAlias, MemoryPermission::None, MemoryPermission::None,
- MemoryAttribute::Mask, MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped));
- CASCADE_CODE(CheckMemoryState(dst_addr, size, MemoryState::All, state, MemoryPermission::None,
- MemoryPermission::None, MemoryAttribute::Mask,
- MemoryAttribute::None));
- CASCADE_CODE(Operate(dst_addr, num_pages, MemoryPermission::None, OperationType::Unmap));
-
- block_manager->Update(dst_addr, num_pages, MemoryState::Free);
- block_manager->Update(src_addr, num_pages, MemoryState::Normal, MemoryPermission::ReadAndWrite);
+ &state, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias,
+ KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
+ KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
+ CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None,
+ KMemoryPermission::None, KMemoryAttribute::Mask,
+ KMemoryAttribute::None));
+ CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
+
+ block_manager->Update(dst_addr, num_pages, KMemoryState::Free);
+ block_manager->Update(src_addr, num_pages, KMemoryState::Normal,
+ KMemoryPermission::ReadAndWrite);
return RESULT_SUCCESS;
}
-void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end) {
+void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) {
auto node{page_linked_list.Nodes().begin()};
PAddr map_addr{node->GetAddress()};
std::size_t src_num_pages{node->GetNumPages()};
- block_manager->IterateForRange(start, end, [&](const MemoryInfo& info) {
- if (info.state != MemoryState::Free) {
+ block_manager->IterateForRange(start, end, [&](const KMemoryInfo& info) {
+ if (info.state != KMemoryState::Free) {
return;
}
@@ -382,7 +384,7 @@ void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start,
}
const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)};
- Operate(dst_addr, num_pages, MemoryPermission::ReadAndWrite, OperationType::Map,
+ Operate(dst_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::Map,
map_addr);
dst_addr += num_pages * PageSize;
@@ -393,14 +395,14 @@ void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start,
});
}
-ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
+ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
std::size_t mapped_size{};
const VAddr end_addr{addr + size};
- block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) {
- if (info.state != MemoryState::Free) {
+ block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) {
+ if (info.state != KMemoryState::Free) {
mapped_size += GetSizeInRange(info, addr, end_addr);
}
});
@@ -409,41 +411,39 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
return RESULT_SUCCESS;
}
- auto process{system.Kernel().CurrentProcess()};
const std::size_t remaining_size{size - mapped_size};
const std::size_t remaining_pages{remaining_size / PageSize};
- if (process->GetResourceLimit() &&
- !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, remaining_size)) {
- return ERR_RESOURCE_LIMIT_EXCEEDED;
+ // Reserve the memory from the process resource limit.
+ KScopedResourceReservation memory_reservation(
+ system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory,
+ remaining_size);
+ if (!memory_reservation.Succeeded()) {
+ LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size);
+ return ResultResourceLimitedExceeded;
}
- PageLinkedList page_linked_list;
- {
- auto block_guard = detail::ScopeExit([&] {
- system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool);
- process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, remaining_size);
- });
+ KPageLinkedList page_linked_list;
- CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages,
- memory_pool));
+ CASCADE_CODE(
+ system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool));
- block_guard.Cancel();
- }
+ // We succeeded, so commit the memory reservation.
+ memory_reservation.Commit();
MapPhysicalMemory(page_linked_list, addr, end_addr);
physical_memory_usage += remaining_size;
const std::size_t num_pages{size / PageSize};
- block_manager->Update(addr, num_pages, MemoryState::Free, MemoryPermission::None,
- MemoryAttribute::None, MemoryState::Normal,
- MemoryPermission::ReadAndWrite, MemoryAttribute::None);
+ block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
+ KMemoryAttribute::None, KMemoryState::Normal,
+ KMemoryPermission::ReadAndWrite, KMemoryAttribute::None);
return RESULT_SUCCESS;
}
-ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
+ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
const VAddr end_addr{addr + size};
@@ -451,15 +451,15 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
std::size_t mapped_size{};
// Verify that the region can be unmapped
- block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) {
- if (info.state == MemoryState::Normal) {
- if (info.attribute != MemoryAttribute::None) {
- result = ERR_INVALID_ADDRESS_STATE;
+ block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) {
+ if (info.state == KMemoryState::Normal) {
+ if (info.attribute != KMemoryAttribute::None) {
+ result = ResultInvalidCurrentMemory;
return;
}
mapped_size += GetSizeInRange(info, addr, end_addr);
- } else if (info.state != MemoryState::Free) {
- result = ERR_INVALID_ADDRESS_STATE;
+ } else if (info.state != KMemoryState::Free) {
+ result = ResultInvalidCurrentMemory;
}
});
@@ -480,23 +480,23 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
return RESULT_SUCCESS;
}
-ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) {
+ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
const VAddr end_addr{addr + size};
ResultCode result{RESULT_SUCCESS};
- PageLinkedList page_linked_list;
+ KPageLinkedList page_linked_list;
// Unmap each region within the range
- block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) {
- if (info.state == MemoryState::Normal) {
+ block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) {
+ if (info.state == KMemoryState::Normal) {
const std::size_t block_size{GetSizeInRange(info, addr, end_addr)};
const std::size_t block_num_pages{block_size / PageSize};
const VAddr block_addr{GetAddressInRange(info, addr)};
AddRegionToPages(block_addr, block_size / PageSize, page_linked_list);
- if (result = Operate(block_addr, block_num_pages, MemoryPermission::None,
+ if (result = Operate(block_addr, block_num_pages, KMemoryPermission::None,
OperationType::Unmap);
result.IsError()) {
return;
@@ -511,93 +511,94 @@ ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) {
const std::size_t num_pages{size / PageSize};
system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool);
- block_manager->Update(addr, num_pages, MemoryState::Free);
+ block_manager->Update(addr, num_pages, KMemoryState::Free);
return RESULT_SUCCESS;
}
-ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
+ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
- MemoryState src_state{};
+ KMemoryState src_state{};
CASCADE_CODE(CheckMemoryState(
- &src_state, nullptr, nullptr, src_addr, size, MemoryState::FlagCanAlias,
- MemoryState::FlagCanAlias, MemoryPermission::Mask, MemoryPermission::ReadAndWrite,
- MemoryAttribute::Mask, MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped));
+ &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
+ KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::ReadAndWrite,
+ KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
if (IsRegionMapped(dst_addr, size)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
- PageLinkedList page_linked_list;
+ KPageLinkedList page_linked_list;
const std::size_t num_pages{size / PageSize};
AddRegionToPages(src_addr, num_pages, page_linked_list);
{
auto block_guard = detail::ScopeExit([&] {
- Operate(src_addr, num_pages, MemoryPermission::ReadAndWrite,
+ Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite,
OperationType::ChangePermissions);
});
- CASCADE_CODE(
- Operate(src_addr, num_pages, MemoryPermission::None, OperationType::ChangePermissions));
- CASCADE_CODE(MapPages(dst_addr, page_linked_list, MemoryPermission::ReadAndWrite));
+ CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None,
+ OperationType::ChangePermissions));
+ CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::ReadAndWrite));
block_guard.Cancel();
}
- block_manager->Update(src_addr, num_pages, src_state, MemoryPermission::None,
- MemoryAttribute::Locked);
- block_manager->Update(dst_addr, num_pages, MemoryState::Stack, MemoryPermission::ReadAndWrite);
+ block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None,
+ KMemoryAttribute::Locked);
+ block_manager->Update(dst_addr, num_pages, KMemoryState::Stack,
+ KMemoryPermission::ReadAndWrite);
return RESULT_SUCCESS;
}
-ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
+ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
- MemoryState src_state{};
+ KMemoryState src_state{};
CASCADE_CODE(CheckMemoryState(
- &src_state, nullptr, nullptr, src_addr, size, MemoryState::FlagCanAlias,
- MemoryState::FlagCanAlias, MemoryPermission::Mask, MemoryPermission::None,
- MemoryAttribute::Mask, MemoryAttribute::Locked, MemoryAttribute::IpcAndDeviceMapped));
-
- MemoryPermission dst_perm{};
- CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, MemoryState::All,
- MemoryState::Stack, MemoryPermission::None,
- MemoryPermission::None, MemoryAttribute::Mask,
- MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped));
-
- PageLinkedList src_pages;
- PageLinkedList dst_pages;
+ &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
+ KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::None,
+ KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
+
+ KMemoryPermission dst_perm{};
+ CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, KMemoryState::All,
+ KMemoryState::Stack, KMemoryPermission::None,
+ KMemoryPermission::None, KMemoryAttribute::Mask,
+ KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
+
+ KPageLinkedList src_pages;
+ KPageLinkedList dst_pages;
const std::size_t num_pages{size / PageSize};
AddRegionToPages(src_addr, num_pages, src_pages);
AddRegionToPages(dst_addr, num_pages, dst_pages);
if (!dst_pages.IsEqual(src_pages)) {
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
{
auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); });
- CASCADE_CODE(Operate(dst_addr, num_pages, MemoryPermission::None, OperationType::Unmap));
- CASCADE_CODE(Operate(src_addr, num_pages, MemoryPermission::ReadAndWrite,
+ CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
+ CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite,
OperationType::ChangePermissions));
block_guard.Cancel();
}
- block_manager->Update(src_addr, num_pages, src_state, MemoryPermission::ReadAndWrite);
- block_manager->Update(dst_addr, num_pages, MemoryState::Free);
+ block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::ReadAndWrite);
+ block_manager->Update(dst_addr, num_pages, KMemoryState::Free);
return RESULT_SUCCESS;
}
-ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_list,
- MemoryPermission perm) {
+ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
+ KMemoryPermission perm) {
VAddr cur_addr{addr};
for (const auto& node : page_linked_list.Nodes()) {
@@ -606,8 +607,8 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
result.IsError()) {
const std::size_t num_pages{(addr - cur_addr) / PageSize};
- ASSERT(
- Operate(addr, num_pages, MemoryPermission::None, OperationType::Unmap).IsSuccess());
+ ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)
+ .IsSuccess());
return result;
}
@@ -618,19 +619,19 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
return RESULT_SUCCESS;
}
-ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state,
- MemoryPermission perm) {
+ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
+ KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
const std::size_t num_pages{page_linked_list.GetNumPages()};
const std::size_t size{num_pages * PageSize};
if (!CanContain(addr, size, state)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (IsRegionMapped(addr, num_pages * PageSize)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
CASCADE_CODE(MapPages(addr, page_linked_list, perm));
@@ -640,26 +641,27 @@ ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, Mem
return RESULT_SUCCESS;
}
-ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm) {
+ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size,
+ KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
- MemoryState prev_state{};
- MemoryPermission prev_perm{};
+ KMemoryState prev_state{};
+ KMemoryPermission prev_perm{};
CASCADE_CODE(CheckMemoryState(
- &prev_state, &prev_perm, nullptr, addr, size, MemoryState::FlagCode, MemoryState::FlagCode,
- MemoryPermission::None, MemoryPermission::None, MemoryAttribute::Mask,
- MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped));
+ &prev_state, &prev_perm, nullptr, addr, size, KMemoryState::FlagCode,
+ KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None,
+ KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
- MemoryState state{prev_state};
+ KMemoryState state{prev_state};
// Ensure state is mutable if permission allows write
- if ((perm & MemoryPermission::Write) != MemoryPermission::None) {
- if (prev_state == MemoryState::Code) {
- state = MemoryState::CodeData;
- } else if (prev_state == MemoryState::AliasCode) {
- state = MemoryState::AliasCodeData;
+ if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) {
+ if (prev_state == KMemoryState::Code) {
+ state = KMemoryState::CodeData;
+ } else if (prev_state == KMemoryState::AliasCode) {
+ state = KMemoryState::AliasCodeData;
} else {
UNREACHABLE();
}
@@ -670,13 +672,13 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo
return RESULT_SUCCESS;
}
- if ((prev_perm & MemoryPermission::Execute) != (perm & MemoryPermission::Execute)) {
+ if ((prev_perm & KMemoryPermission::Execute) != (perm & KMemoryPermission::Execute)) {
// Memory execution state is changing, invalidate CPU cache range
system.InvalidateCpuInstructionCacheRange(addr, size);
}
const std::size_t num_pages{size / PageSize};
- const OperationType operation{(perm & MemoryPermission::Execute) != MemoryPermission::None
+ const OperationType operation{(perm & KMemoryPermission::Execute) != KMemoryPermission::None
? OperationType::ChangePermissionsAndRefresh
: OperationType::ChangePermissions};
@@ -687,69 +689,69 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo
return RESULT_SUCCESS;
}
-MemoryInfo PageTable::QueryInfoImpl(VAddr addr) {
+KMemoryInfo KPageTable::QueryInfoImpl(VAddr addr) {
std::lock_guard lock{page_table_lock};
return block_manager->FindBlock(addr).GetMemoryInfo();
}
-MemoryInfo PageTable::QueryInfo(VAddr addr) {
+KMemoryInfo KPageTable::QueryInfo(VAddr addr) {
if (!Contains(addr, 1)) {
- return {address_space_end, 0 - address_space_end, MemoryState::Inaccessible,
- MemoryPermission::None, MemoryAttribute::None, MemoryPermission::None};
+ return {address_space_end, 0 - address_space_end, KMemoryState::Inaccessible,
+ KMemoryPermission::None, KMemoryAttribute::None, KMemoryPermission::None};
}
return QueryInfoImpl(addr);
}
-ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm) {
+ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
- MemoryState state{};
- MemoryAttribute attribute{};
+ KMemoryState state{};
+ KMemoryAttribute attribute{};
- CASCADE_CODE(CheckMemoryState(&state, nullptr, &attribute, addr, size,
- MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted,
- MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted,
- MemoryPermission::Mask, MemoryPermission::ReadAndWrite,
- MemoryAttribute::Mask, MemoryAttribute::None,
- MemoryAttribute::IpcAndDeviceMapped));
+ CASCADE_CODE(CheckMemoryState(
+ &state, nullptr, &attribute, addr, size,
+ KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
+ KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::Mask,
+ KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None,
+ KMemoryAttribute::IpcAndDeviceMapped));
- block_manager->Update(addr, size / PageSize, state, perm, attribute | MemoryAttribute::Locked);
+ block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked);
return RESULT_SUCCESS;
}
-ResultCode PageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
+ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
- MemoryState state{};
+ KMemoryState state{};
- CASCADE_CODE(CheckMemoryState(&state, nullptr, nullptr, addr, size,
- MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted,
- MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted,
- MemoryPermission::None, MemoryPermission::None,
- MemoryAttribute::Mask, MemoryAttribute::Locked,
- MemoryAttribute::IpcAndDeviceMapped));
+ CASCADE_CODE(
+ CheckMemoryState(&state, nullptr, nullptr, addr, size,
+ KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
+ KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
+ KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
+ KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
- block_manager->Update(addr, size / PageSize, state, MemoryPermission::ReadAndWrite);
+ block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite);
return RESULT_SUCCESS;
}
-ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask,
- MemoryAttribute value) {
+ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask,
+ KMemoryAttribute value) {
std::lock_guard lock{page_table_lock};
- MemoryState state{};
- MemoryPermission perm{};
- MemoryAttribute attribute{};
+ KMemoryState state{};
+ KMemoryPermission perm{};
+ KMemoryAttribute attribute{};
- CASCADE_CODE(CheckMemoryState(&state, &perm, &attribute, addr, size,
- MemoryState::FlagCanChangeAttribute,
- MemoryState::FlagCanChangeAttribute, MemoryPermission::None,
- MemoryPermission::None, MemoryAttribute::LockedAndIpcLocked,
- MemoryAttribute::None, MemoryAttribute::DeviceSharedAndUncached));
+ CASCADE_CODE(CheckMemoryState(
+ &state, &perm, &attribute, addr, size, KMemoryState::FlagCanChangeAttribute,
+ KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
+ KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
+ KMemoryAttribute::DeviceSharedAndUncached));
attribute = attribute & ~mask;
attribute = attribute | (mask & value);
@@ -759,16 +761,16 @@ ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAtt
return RESULT_SUCCESS;
}
-ResultCode PageTable::SetHeapCapacity(std::size_t new_heap_capacity) {
+ResultCode KPageTable::SetHeapCapacity(std::size_t new_heap_capacity) {
std::lock_guard lock{page_table_lock};
heap_capacity = new_heap_capacity;
return RESULT_SUCCESS;
}
-ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
+ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) {
if (size > heap_region_end - heap_region_start) {
- return ERR_OUT_OF_MEMORY;
+ return ResultOutOfMemory;
}
const u64 previous_heap_size{GetHeapSize()};
@@ -781,27 +783,34 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
const u64 delta{size - previous_heap_size};
- auto process{system.Kernel().CurrentProcess()};
- if (process->GetResourceLimit() && delta != 0 &&
- !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, delta)) {
- return ERR_RESOURCE_LIMIT_EXCEEDED;
+ // Reserve memory for the heap extension.
+ KScopedResourceReservation memory_reservation(
+ system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory,
+ delta);
+
+ if (!memory_reservation.Succeeded()) {
+ LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta);
+ return ResultResourceLimitedExceeded;
}
- PageLinkedList page_linked_list;
+ KPageLinkedList page_linked_list;
const std::size_t num_pages{delta / PageSize};
CASCADE_CODE(
system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool));
if (IsRegionMapped(current_heap_addr, delta)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
CASCADE_CODE(
Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup));
- block_manager->Update(current_heap_addr, num_pages, MemoryState::Normal,
- MemoryPermission::ReadAndWrite);
+ // Succeeded in allocation, commit the resource reservation
+ memory_reservation.Commit();
+
+ block_manager->Update(current_heap_addr, num_pages, KMemoryState::Normal,
+ KMemoryPermission::ReadAndWrite);
current_heap_addr = heap_region_start + size;
}
@@ -809,30 +818,30 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
return MakeResult<VAddr>(heap_region_start);
}
-ResultVal<VAddr> PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
- bool is_map_only, VAddr region_start,
- std::size_t region_num_pages, MemoryState state,
- MemoryPermission perm, PAddr map_addr) {
+ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
+ bool is_map_only, VAddr region_start,
+ std::size_t region_num_pages, KMemoryState state,
+ KMemoryPermission perm, PAddr map_addr) {
std::lock_guard lock{page_table_lock};
if (!CanContain(region_start, region_num_pages * PageSize, state)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (region_num_pages <= needed_num_pages) {
- return ERR_OUT_OF_MEMORY;
+ return ResultOutOfMemory;
}
const VAddr addr{
AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)};
if (!addr) {
- return ERR_OUT_OF_MEMORY;
+ return ResultOutOfMemory;
}
if (is_map_only) {
CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
} else {
- PageLinkedList page_group;
+ KPageLinkedList page_group;
CASCADE_CODE(
system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool));
CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup));
@@ -843,22 +852,22 @@ ResultVal<VAddr> PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s
return MakeResult<VAddr>(addr);
}
-ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
+ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
- MemoryPermission perm{};
+ KMemoryPermission perm{};
if (const ResultCode result{CheckMemoryState(
- nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute,
- MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None,
- MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None,
- MemoryAttribute::DeviceSharedAndUncached)};
+ nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
+ KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
+ KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
+ KMemoryAttribute::DeviceSharedAndUncached)};
result.IsError()) {
return result;
}
block_manager->UpdateLock(
addr, size / PageSize,
- [](MemoryBlockManager::iterator block, MemoryPermission perm) {
+ [](KMemoryBlockManager::iterator block, KMemoryPermission perm) {
block->ShareToDevice(perm);
},
perm);
@@ -866,22 +875,22 @@ ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
return RESULT_SUCCESS;
}
-ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
+ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
std::lock_guard lock{page_table_lock};
- MemoryPermission perm{};
+ KMemoryPermission perm{};
if (const ResultCode result{CheckMemoryState(
- nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute,
- MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None,
- MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None,
- MemoryAttribute::DeviceSharedAndUncached)};
+ nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
+ KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
+ KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
+ KMemoryAttribute::DeviceSharedAndUncached)};
result.IsError()) {
return result;
}
block_manager->UpdateLock(
addr, size / PageSize,
- [](MemoryBlockManager::iterator block, MemoryPermission perm) {
+ [](KMemoryBlockManager::iterator block, KMemoryPermission perm) {
block->UnshareToDevice(perm);
},
perm);
@@ -889,20 +898,21 @@ ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
return RESULT_SUCCESS;
}
-ResultCode PageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
- block_manager = std::make_unique<MemoryBlockManager>(start, end);
+ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
+ block_manager = std::make_unique<KMemoryBlockManager>(start, end);
return RESULT_SUCCESS;
}
-bool PageTable::IsRegionMapped(VAddr address, u64 size) {
- return CheckMemoryState(address, size, MemoryState::All, MemoryState::Free,
- MemoryPermission::Mask, MemoryPermission::None, MemoryAttribute::Mask,
- MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)
+bool KPageTable::IsRegionMapped(VAddr address, u64 size) {
+ return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
+ KMemoryPermission::Mask, KMemoryPermission::None,
+ KMemoryAttribute::Mask, KMemoryAttribute::None,
+ KMemoryAttribute::IpcAndDeviceMapped)
.IsError();
}
-bool PageTable::IsRegionContiguous(VAddr addr, u64 size) const {
+bool KPageTable::IsRegionContiguous(VAddr addr, u64 size) const {
auto start_ptr = system.Memory().GetPointer(addr);
for (u64 offset{}; offset < size; offset += PageSize) {
if (start_ptr != system.Memory().GetPointer(addr + offset)) {
@@ -913,8 +923,8 @@ bool PageTable::IsRegionContiguous(VAddr addr, u64 size) const {
return true;
}
-void PageTable::AddRegionToPages(VAddr start, std::size_t num_pages,
- PageLinkedList& page_linked_list) {
+void KPageTable::AddRegionToPages(VAddr start, std::size_t num_pages,
+ KPageLinkedList& page_linked_list) {
VAddr addr{start};
while (addr < start + (num_pages * PageSize)) {
const PAddr paddr{GetPhysicalAddr(addr)};
@@ -926,8 +936,8 @@ void PageTable::AddRegionToPages(VAddr start, std::size_t num_pages,
}
}
-VAddr PageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages,
- u64 needed_num_pages, std::size_t align) {
+VAddr KPageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages,
+ u64 needed_num_pages, std::size_t align) {
if (is_aslr_enabled) {
UNIMPLEMENTED();
}
@@ -935,8 +945,8 @@ VAddr PageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages
IsKernel() ? 1 : 4);
}
-ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group,
- OperationType operation) {
+ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group,
+ OperationType operation) {
std::lock_guard lock{page_table_lock};
ASSERT(Common::IsAligned(addr, PageSize));
@@ -960,8 +970,8 @@ ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinke
return RESULT_SUCCESS;
}
-ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm,
- OperationType operation, PAddr map_addr) {
+ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
+ OperationType operation, PAddr map_addr) {
std::lock_guard lock{page_table_lock};
ASSERT(num_pages > 0);
@@ -987,34 +997,34 @@ ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, MemoryPermissio
return RESULT_SUCCESS;
}
-constexpr VAddr PageTable::GetRegionAddress(MemoryState state) const {
+constexpr VAddr KPageTable::GetRegionAddress(KMemoryState state) const {
switch (state) {
- case MemoryState::Free:
- case MemoryState::Kernel:
+ case KMemoryState::Free:
+ case KMemoryState::Kernel:
return address_space_start;
- case MemoryState::Normal:
+ case KMemoryState::Normal:
return heap_region_start;
- case MemoryState::Ipc:
- case MemoryState::NonSecureIpc:
- case MemoryState::NonDeviceIpc:
+ case KMemoryState::Ipc:
+ case KMemoryState::NonSecureIpc:
+ case KMemoryState::NonDeviceIpc:
return alias_region_start;
- case MemoryState::Stack:
+ case KMemoryState::Stack:
return stack_region_start;
- case MemoryState::Io:
- case MemoryState::Static:
- case MemoryState::ThreadLocal:
+ case KMemoryState::Io:
+ case KMemoryState::Static:
+ case KMemoryState::ThreadLocal:
return kernel_map_region_start;
- case MemoryState::Shared:
- case MemoryState::AliasCode:
- case MemoryState::AliasCodeData:
- case MemoryState::Transferred:
- case MemoryState::SharedTransferred:
- case MemoryState::SharedCode:
- case MemoryState::GeneratedCode:
- case MemoryState::CodeOut:
+ case KMemoryState::Shared:
+ case KMemoryState::AliasCode:
+ case KMemoryState::AliasCodeData:
+ case KMemoryState::Transferred:
+ case KMemoryState::SharedTransferred:
+ case KMemoryState::SharedCode:
+ case KMemoryState::GeneratedCode:
+ case KMemoryState::CodeOut:
return alias_code_region_start;
- case MemoryState::Code:
- case MemoryState::CodeData:
+ case KMemoryState::Code:
+ case KMemoryState::CodeData:
return code_region_start;
default:
UNREACHABLE();
@@ -1022,34 +1032,34 @@ constexpr VAddr PageTable::GetRegionAddress(MemoryState state) const {
}
}
-constexpr std::size_t PageTable::GetRegionSize(MemoryState state) const {
+constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
switch (state) {
- case MemoryState::Free:
- case MemoryState::Kernel:
+ case KMemoryState::Free:
+ case KMemoryState::Kernel:
return address_space_end - address_space_start;
- case MemoryState::Normal:
+ case KMemoryState::Normal:
return heap_region_end - heap_region_start;
- case MemoryState::Ipc:
- case MemoryState::NonSecureIpc:
- case MemoryState::NonDeviceIpc:
+ case KMemoryState::Ipc:
+ case KMemoryState::NonSecureIpc:
+ case KMemoryState::NonDeviceIpc:
return alias_region_end - alias_region_start;
- case MemoryState::Stack:
+ case KMemoryState::Stack:
return stack_region_end - stack_region_start;
- case MemoryState::Io:
- case MemoryState::Static:
- case MemoryState::ThreadLocal:
+ case KMemoryState::Io:
+ case KMemoryState::Static:
+ case KMemoryState::ThreadLocal:
return kernel_map_region_end - kernel_map_region_start;
- case MemoryState::Shared:
- case MemoryState::AliasCode:
- case MemoryState::AliasCodeData:
- case MemoryState::Transferred:
- case MemoryState::SharedTransferred:
- case MemoryState::SharedCode:
- case MemoryState::GeneratedCode:
- case MemoryState::CodeOut:
+ case KMemoryState::Shared:
+ case KMemoryState::AliasCode:
+ case KMemoryState::AliasCodeData:
+ case KMemoryState::Transferred:
+ case KMemoryState::SharedTransferred:
+ case KMemoryState::SharedCode:
+ case KMemoryState::GeneratedCode:
+ case KMemoryState::CodeOut:
return alias_code_region_end - alias_code_region_start;
- case MemoryState::Code:
- case MemoryState::CodeData:
+ case KMemoryState::Code:
+ case KMemoryState::CodeData:
return code_region_end - code_region_start;
default:
UNREACHABLE();
@@ -1057,7 +1067,7 @@ constexpr std::size_t PageTable::GetRegionSize(MemoryState state) const {
}
}
-constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState state) const {
+constexpr bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const {
const VAddr end{addr + size};
const VAddr last{end - 1};
const VAddr region_start{GetRegionAddress(state)};
@@ -1068,30 +1078,30 @@ constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState s
const bool is_in_alias{!(end <= alias_region_start || alias_region_end <= addr)};
switch (state) {
- case MemoryState::Free:
- case MemoryState::Kernel:
+ case KMemoryState::Free:
+ case KMemoryState::Kernel:
return is_in_region;
- case MemoryState::Io:
- case MemoryState::Static:
- case MemoryState::Code:
- case MemoryState::CodeData:
- case MemoryState::Shared:
- case MemoryState::AliasCode:
- case MemoryState::AliasCodeData:
- case MemoryState::Stack:
- case MemoryState::ThreadLocal:
- case MemoryState::Transferred:
- case MemoryState::SharedTransferred:
- case MemoryState::SharedCode:
- case MemoryState::GeneratedCode:
- case MemoryState::CodeOut:
+ case KMemoryState::Io:
+ case KMemoryState::Static:
+ case KMemoryState::Code:
+ case KMemoryState::CodeData:
+ case KMemoryState::Shared:
+ case KMemoryState::AliasCode:
+ case KMemoryState::AliasCodeData:
+ case KMemoryState::Stack:
+ case KMemoryState::ThreadLocal:
+ case KMemoryState::Transferred:
+ case KMemoryState::SharedTransferred:
+ case KMemoryState::SharedCode:
+ case KMemoryState::GeneratedCode:
+ case KMemoryState::CodeOut:
return is_in_region && !is_in_heap && !is_in_alias;
- case MemoryState::Normal:
+ case KMemoryState::Normal:
ASSERT(is_in_heap);
return is_in_region && !is_in_alias;
- case MemoryState::Ipc:
- case MemoryState::NonSecureIpc:
- case MemoryState::NonDeviceIpc:
+ case KMemoryState::Ipc:
+ case KMemoryState::NonSecureIpc:
+ case KMemoryState::NonDeviceIpc:
ASSERT(is_in_alias);
return is_in_region && !is_in_heap;
default:
@@ -1099,53 +1109,54 @@ constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState s
}
}
-constexpr ResultCode PageTable::CheckMemoryState(const MemoryInfo& info, MemoryState state_mask,
- MemoryState state, MemoryPermission perm_mask,
- MemoryPermission perm, MemoryAttribute attr_mask,
- MemoryAttribute attr) const {
+constexpr ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask,
+ KMemoryPermission perm,
+ KMemoryAttribute attr_mask,
+ KMemoryAttribute attr) const {
// Validate the states match expectation
if ((info.state & state_mask) != state) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if ((info.perm & perm_mask) != perm) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if ((info.attribute & attr_mask) != attr) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
return RESULT_SUCCESS;
}
-ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission* out_perm,
- MemoryAttribute* out_attr, VAddr addr, std::size_t size,
- MemoryState state_mask, MemoryState state,
- MemoryPermission perm_mask, MemoryPermission perm,
- MemoryAttribute attr_mask, MemoryAttribute attr,
- MemoryAttribute ignore_attr) {
+ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
+ KMemoryAttribute* out_attr, VAddr addr, std::size_t size,
+ KMemoryState state_mask, KMemoryState state,
+ KMemoryPermission perm_mask, KMemoryPermission perm,
+ KMemoryAttribute attr_mask, KMemoryAttribute attr,
+ KMemoryAttribute ignore_attr) {
std::lock_guard lock{page_table_lock};
// Get information about the first block
const VAddr last_addr{addr + size - 1};
- MemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)};
- MemoryInfo info{it->GetMemoryInfo()};
+ KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)};
+ KMemoryInfo info{it->GetMemoryInfo()};
// Validate all blocks in the range have correct state
- const MemoryState first_state{info.state};
- const MemoryPermission first_perm{info.perm};
- const MemoryAttribute first_attr{info.attribute};
+ const KMemoryState first_state{info.state};
+ const KMemoryPermission first_perm{info.perm};
+ const KMemoryAttribute first_attr{info.attribute};
while (true) {
// Validate the current block
if (!(info.state == first_state)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (!(info.perm == first_perm)) {
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
- if (!((info.attribute | static_cast<MemoryAttribute>(ignore_attr)) ==
- (first_attr | static_cast<MemoryAttribute>(ignore_attr)))) {
- return ERR_INVALID_ADDRESS_STATE;
+ if (!((info.attribute | static_cast<KMemoryAttribute>(ignore_attr)) ==
+ (first_attr | static_cast<KMemoryAttribute>(ignore_attr)))) {
+ return ResultInvalidCurrentMemory;
}
// Validate against the provided masks
@@ -1170,10 +1181,10 @@ ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission*
*out_perm = first_perm;
}
if (out_attr) {
- *out_attr = first_attr & static_cast<MemoryAttribute>(~ignore_attr);
+ *out_attr = first_attr & static_cast<KMemoryAttribute>(~ignore_attr);
}
return RESULT_SUCCESS;
}
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/k_page_table.h
index ce0d38849..49b824379 100644
--- a/src/core/hle/kernel/memory/page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -10,27 +10,27 @@
#include "common/common_types.h"
#include "common/page_table.h"
#include "core/file_sys/program_metadata.h"
-#include "core/hle/kernel/memory/memory_block.h"
-#include "core/hle/kernel/memory/memory_manager.h"
+#include "core/hle/kernel/k_memory_block.h"
+#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/result.h"
namespace Core {
class System;
}
-namespace Kernel::Memory {
+namespace Kernel {
-class MemoryBlockManager;
+class KMemoryBlockManager;
-class PageTable final : NonCopyable {
+class KPageTable final : NonCopyable {
public:
- explicit PageTable(Core::System& system);
+ explicit KPageTable(Core::System& system);
ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
VAddr code_addr, std::size_t code_size,
- Memory::MemoryManager::Pool pool);
- ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, MemoryState state,
- MemoryPermission perm);
+ KMemoryManager::Pool pool);
+ ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
+ KMemoryPermission perm);
ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
@@ -38,20 +38,20 @@ public:
ResultCode UnmapMemory(VAddr addr, std::size_t size);
ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size);
- ResultCode MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state,
- MemoryPermission perm);
- ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm);
- MemoryInfo QueryInfo(VAddr addr);
- ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm);
+ ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
+ KMemoryPermission perm);
+ ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
+ KMemoryInfo QueryInfo(VAddr addr);
+ ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
- ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask,
- MemoryAttribute value);
+ ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask,
+ KMemoryAttribute value);
ResultCode SetHeapCapacity(std::size_t new_heap_capacity);
ResultVal<VAddr> SetHeapSize(std::size_t size);
ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
bool is_map_only, VAddr region_start,
- std::size_t region_num_pages, MemoryState state,
- MemoryPermission perm, PAddr map_addr = 0);
+ std::size_t region_num_pages, KMemoryState state,
+ KMemoryPermission perm, PAddr map_addr = 0);
ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
@@ -72,47 +72,49 @@ private:
ChangePermissionsAndRefresh,
};
- static constexpr MemoryAttribute DefaultMemoryIgnoreAttr =
- MemoryAttribute::DontCareMask | MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared;
+ static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr = KMemoryAttribute::DontCareMask |
+ KMemoryAttribute::IpcLocked |
+ KMemoryAttribute::DeviceShared;
ResultCode InitializeMemoryLayout(VAddr start, VAddr end);
- ResultCode MapPages(VAddr addr, const PageLinkedList& page_linked_list, MemoryPermission perm);
- void MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end);
+ ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
+ KMemoryPermission perm);
+ void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end);
bool IsRegionMapped(VAddr address, u64 size);
bool IsRegionContiguous(VAddr addr, u64 size) const;
- void AddRegionToPages(VAddr start, std::size_t num_pages, PageLinkedList& page_linked_list);
- MemoryInfo QueryInfoImpl(VAddr addr);
+ void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list);
+ KMemoryInfo QueryInfoImpl(VAddr addr);
VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages,
std::size_t align);
- ResultCode Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group,
+ ResultCode Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group,
OperationType operation);
- ResultCode Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm,
+ ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
OperationType operation, PAddr map_addr = 0);
- constexpr VAddr GetRegionAddress(MemoryState state) const;
- constexpr std::size_t GetRegionSize(MemoryState state) const;
- constexpr bool CanContain(VAddr addr, std::size_t size, MemoryState state) const;
+ constexpr VAddr GetRegionAddress(KMemoryState state) const;
+ constexpr std::size_t GetRegionSize(KMemoryState state) const;
+ constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const;
- constexpr ResultCode CheckMemoryState(const MemoryInfo& info, MemoryState state_mask,
- MemoryState state, MemoryPermission perm_mask,
- MemoryPermission perm, MemoryAttribute attr_mask,
- MemoryAttribute attr) const;
- ResultCode CheckMemoryState(MemoryState* out_state, MemoryPermission* out_perm,
- MemoryAttribute* out_attr, VAddr addr, std::size_t size,
- MemoryState state_mask, MemoryState state,
- MemoryPermission perm_mask, MemoryPermission perm,
- MemoryAttribute attr_mask, MemoryAttribute attr,
- MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr);
- ResultCode CheckMemoryState(VAddr addr, std::size_t size, MemoryState state_mask,
- MemoryState state, MemoryPermission perm_mask,
- MemoryPermission perm, MemoryAttribute attr_mask,
- MemoryAttribute attr,
- MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) {
+ constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask,
+ KMemoryPermission perm, KMemoryAttribute attr_mask,
+ KMemoryAttribute attr) const;
+ ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
+ KMemoryAttribute* out_attr, VAddr addr, std::size_t size,
+ KMemoryState state_mask, KMemoryState state,
+ KMemoryPermission perm_mask, KMemoryPermission perm,
+ KMemoryAttribute attr_mask, KMemoryAttribute attr,
+ KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr);
+ ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask,
+ KMemoryPermission perm, KMemoryAttribute attr_mask,
+ KMemoryAttribute attr,
+ KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) {
return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
perm, attr_mask, attr, ignore_attr);
}
std::recursive_mutex page_table_lock;
- std::unique_ptr<MemoryBlockManager> block_manager;
+ std::unique_ptr<KMemoryBlockManager> block_manager;
public:
constexpr VAddr GetAddressSpaceStart() const {
@@ -212,7 +214,7 @@ public:
return !IsOutsideASLRRegion(address, size);
}
constexpr PAddr GetPhysicalAddr(VAddr addr) {
- return page_table_impl.backing_addr[addr >> Memory::PageBits] + addr;
+ return page_table_impl.backing_addr[addr >> PageBits] + addr;
}
private:
@@ -267,11 +269,11 @@ private:
bool is_kernel{};
bool is_aslr_enabled{};
- MemoryManager::Pool memory_pool{MemoryManager::Pool::Application};
+ KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application};
Common::PageTable page_table_impl;
Core::System& system;
};
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_readable_event.cpp b/src/core/hle/kernel/k_readable_event.cpp
index d8a42dbaf..4b4d34857 100644
--- a/src/core/hle/kernel/k_readable_event.cpp
+++ b/src/core/hle/kernel/k_readable_event.cpp
@@ -6,7 +6,6 @@
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
@@ -47,7 +46,7 @@ ResultCode KReadableEvent::Reset() {
KScopedSchedulerLock lk{kernel};
if (!is_signaled) {
- return Svc::ResultInvalidState;
+ return ResultInvalidState;
}
is_signaled = false;
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
index ab2ab683f..d7a4a38e6 100644
--- a/src/core/hle/kernel/k_resource_limit.cpp
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -75,7 +75,7 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
const auto index = static_cast<std::size_t>(which);
KScopedLightLock lk(lock);
- R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState);
+ R_UNLESS(current_values[index] <= value, ResultInvalidState);
limit_values[index] = value;
diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h
new file mode 100644
index 000000000..c5deca00b
--- /dev/null
+++ b/src/core/hle/kernel/k_scoped_resource_reservation.h
@@ -0,0 +1,67 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// This file references various implementation details from Atmosphere, an open-source firmware for
+// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/process.h"
+
+namespace Kernel {
+
+class KScopedResourceReservation {
+public:
+ explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
+ s64 v, s64 timeout)
+ : resource_limit(std::move(l)), value(v), resource(r) {
+ if (resource_limit && value) {
+ success = resource_limit->Reserve(resource, value, timeout);
+ } else {
+ success = true;
+ }
+ }
+
+ explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
+ s64 v = 1)
+ : resource_limit(std::move(l)), value(v), resource(r) {
+ if (resource_limit && value) {
+ success = resource_limit->Reserve(resource, value);
+ } else {
+ success = true;
+ }
+ }
+
+ explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v, s64 t)
+ : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {}
+
+ explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v = 1)
+ : KScopedResourceReservation(p->GetResourceLimit(), r, v) {}
+
+ ~KScopedResourceReservation() noexcept {
+ if (resource_limit && value && success) {
+ // resource was not committed, release the reservation.
+ resource_limit->Release(resource, value);
+ }
+ }
+
+ /// Commit the resource reservation, destruction of this object does not release the resource
+ void Commit() {
+ resource_limit = nullptr;
+ }
+
+ [[nodiscard]] bool Succeeded() const {
+ return success;
+ }
+
+private:
+ std::shared_ptr<KResourceLimit> resource_limit;
+ s64 value;
+ LimitableResource resource;
+ bool success;
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp
new file mode 100644
index 000000000..9b14f42b5
--- /dev/null
+++ b/src/core/hle/kernel/k_shared_memory.cpp
@@ -0,0 +1,65 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+KSharedMemory::KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory)
+ : Object{kernel}, device_memory{device_memory} {}
+
+KSharedMemory::~KSharedMemory() {
+ kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size);
+}
+
+std::shared_ptr<KSharedMemory> KSharedMemory::Create(
+ KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,
+ KPageLinkedList&& page_list, KMemoryPermission owner_permission,
+ KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) {
+
+ const auto resource_limit = kernel.GetSystemResourceLimit();
+ KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
+ size);
+ ASSERT(memory_reservation.Succeeded());
+
+ std::shared_ptr<KSharedMemory> shared_memory{
+ std::make_shared<KSharedMemory>(kernel, device_memory)};
+
+ shared_memory->owner_process = owner_process;
+ shared_memory->page_list = std::move(page_list);
+ shared_memory->owner_permission = owner_permission;
+ shared_memory->user_permission = user_permission;
+ shared_memory->physical_address = physical_address;
+ shared_memory->size = size;
+ shared_memory->name = name;
+
+ memory_reservation.Commit();
+ return shared_memory;
+}
+
+ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size,
+ KMemoryPermission permissions) {
+ const u64 page_count{(size + PageSize - 1) / PageSize};
+
+ if (page_list.GetNumPages() != page_count) {
+ UNIMPLEMENTED_MSG("Page count does not match");
+ }
+
+ const KMemoryPermission expected =
+ &target_process == owner_process ? owner_permission : user_permission;
+
+ if (permissions != expected) {
+ UNIMPLEMENTED_MSG("Permission does not match");
+ }
+
+ return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared,
+ permissions);
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/k_shared_memory.h
index 623bd8b11..016e34be5 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/k_shared_memory.h
@@ -9,8 +9,8 @@
#include "common/common_types.h"
#include "core/device_memory.h"
-#include "core/hle/kernel/memory/memory_block.h"
-#include "core/hle/kernel/memory/page_linked_list.h"
+#include "core/hle/kernel/k_memory_block.h"
+#include "core/hle/kernel/k_page_linked_list.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/result.h"
@@ -19,15 +19,15 @@ namespace Kernel {
class KernelCore;
-class SharedMemory final : public Object {
+class KSharedMemory final : public Object {
public:
- explicit SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory);
- ~SharedMemory() override;
+ explicit KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory);
+ ~KSharedMemory() override;
- static std::shared_ptr<SharedMemory> Create(
+ static std::shared_ptr<KSharedMemory> Create(
KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,
- Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission,
- Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size,
+ KPageLinkedList&& page_list, KMemoryPermission owner_permission,
+ KMemoryPermission user_permission, PAddr physical_address, std::size_t size,
std::string name);
std::string GetTypeName() const override {
@@ -51,7 +51,7 @@ public:
* @param permissions Memory block map permissions (specified by SVC field)
*/
ResultCode Map(Process& target_process, VAddr address, std::size_t size,
- Memory::MemoryPermission permissions);
+ KMemoryPermission permissions);
/**
* Gets a pointer to the shared memory block
@@ -76,9 +76,9 @@ public:
private:
Core::DeviceMemory& device_memory;
Process* owner_process{};
- Memory::PageLinkedList page_list;
- Memory::MemoryPermission owner_permission{};
- Memory::MemoryPermission user_permission{};
+ KPageLinkedList page_list;
+ KMemoryPermission owner_permission{};
+ KMemoryPermission user_permission{};
PAddr physical_address{};
std::size_t size{};
std::string name;
diff --git a/src/core/hle/kernel/memory/slab_heap.h b/src/core/hle/kernel/k_slab_heap.h
index 465eaddb3..aa4471d2f 100644
--- a/src/core/hle/kernel/memory/slab_heap.h
+++ b/src/core/hle/kernel/k_slab_heap.h
@@ -2,9 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#pragma once
#include <atomic>
@@ -12,17 +9,17 @@
#include "common/assert.h"
#include "common/common_types.h"
-namespace Kernel::Memory {
+namespace Kernel {
namespace impl {
-class SlabHeapImpl final : NonCopyable {
+class KSlabHeapImpl final : NonCopyable {
public:
struct Node {
Node* next{};
};
- constexpr SlabHeapImpl() = default;
+ constexpr KSlabHeapImpl() = default;
void Initialize(std::size_t size) {
ASSERT(head == nullptr);
@@ -65,9 +62,9 @@ private:
} // namespace impl
-class SlabHeapBase : NonCopyable {
+class KSlabHeapBase : NonCopyable {
public:
- constexpr SlabHeapBase() = default;
+ constexpr KSlabHeapBase() = default;
constexpr bool Contains(uintptr_t addr) const {
return start <= addr && addr < end;
@@ -126,7 +123,7 @@ public:
}
private:
- using Impl = impl::SlabHeapImpl;
+ using Impl = impl::KSlabHeapImpl;
Impl impl;
uintptr_t peak{};
@@ -135,9 +132,9 @@ private:
};
template <typename T>
-class SlabHeap final : public SlabHeapBase {
+class KSlabHeap final : public KSlabHeapBase {
public:
- constexpr SlabHeap() : SlabHeapBase() {}
+ constexpr KSlabHeap() : KSlabHeapBase() {}
void Initialize(void* memory, std::size_t memory_size) {
InitializeImpl(sizeof(T), memory, memory_size);
@@ -160,4 +157,4 @@ public:
}
};
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_spin_lock.cpp b/src/core/hle/kernel/k_spin_lock.cpp
new file mode 100644
index 000000000..4412aa4bb
--- /dev/null
+++ b/src/core/hle/kernel/k_spin_lock.cpp
@@ -0,0 +1,54 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_spin_lock.h"
+
+#if _MSC_VER
+#include <intrin.h>
+#if _M_AMD64
+#define __x86_64__ 1
+#endif
+#if _M_ARM64
+#define __aarch64__ 1
+#endif
+#else
+#if __x86_64__
+#include <xmmintrin.h>
+#endif
+#endif
+
+namespace {
+
+void ThreadPause() {
+#if __x86_64__
+ _mm_pause();
+#elif __aarch64__ && _MSC_VER
+ __yield();
+#elif __aarch64__
+ asm("yield");
+#endif
+}
+
+} // namespace
+
+namespace Kernel {
+
+void KSpinLock::Lock() {
+ while (lck.test_and_set(std::memory_order_acquire)) {
+ ThreadPause();
+ }
+}
+
+void KSpinLock::Unlock() {
+ lck.clear(std::memory_order_release);
+}
+
+bool KSpinLock::TryLock() {
+ if (lck.test_and_set(std::memory_order_acquire)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_spin_lock.h b/src/core/hle/kernel/k_spin_lock.h
new file mode 100644
index 000000000..12c4b2e88
--- /dev/null
+++ b/src/core/hle/kernel/k_spin_lock.h
@@ -0,0 +1,33 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+
+#include "core/hle/kernel/k_scoped_lock.h"
+
+namespace Kernel {
+
+class KSpinLock {
+public:
+ KSpinLock() = default;
+
+ KSpinLock(const KSpinLock&) = delete;
+ KSpinLock& operator=(const KSpinLock&) = delete;
+
+ KSpinLock(KSpinLock&&) = delete;
+ KSpinLock& operator=(KSpinLock&&) = delete;
+
+ void Lock();
+ void Unlock();
+ [[nodiscard]] bool TryLock();
+
+private:
+ std::atomic_flag lck = ATOMIC_FLAG_INIT;
+};
+
+using KScopedSpinLock = KScopedLock<KSpinLock>;
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp
index 140cc46a7..82f72a0fe 100644
--- a/src/core/hle/kernel/k_synchronization_object.cpp
+++ b/src/core/hle/kernel/k_synchronization_object.cpp
@@ -40,20 +40,20 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
// Check if the timeout is zero.
if (timeout == 0) {
slp.CancelSleep();
- return Svc::ResultTimedOut;
+ return ResultTimedOut;
}
// Check if the thread should terminate.
if (thread->IsTerminationRequested()) {
slp.CancelSleep();
- return Svc::ResultTerminationRequested;
+ return ResultTerminationRequested;
}
// Check if waiting was canceled.
if (thread->IsWaitCancelled()) {
slp.CancelSleep();
thread->ClearWaitCancelled();
- return Svc::ResultCancelled;
+ return ResultCancelled;
}
// Add the waiters.
@@ -75,7 +75,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
// Mark the thread as waiting.
thread->SetCancellable();
- thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
+ thread->SetSyncedObject(nullptr, ResultTimedOut);
thread->SetState(ThreadState::Waiting);
thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization);
}
diff --git a/src/core/hle/kernel/memory/system_control.cpp b/src/core/hle/kernel/k_system_control.cpp
index 11d204bc2..aa1682f69 100644
--- a/src/core/hle/kernel/memory/system_control.cpp
+++ b/src/core/hle/kernel/k_system_control.cpp
@@ -1,12 +1,13 @@
-// Copyright 2020 yuzu Emulator Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <random>
-#include "core/hle/kernel/memory/system_control.h"
+#include "core/hle/kernel/k_system_control.h"
+
+namespace Kernel {
-namespace Kernel::Memory::SystemControl {
namespace {
template <typename F>
u64 GenerateUniformRange(u64 min, u64 max, F f) {
@@ -25,16 +26,17 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) {
}
}
-u64 GenerateRandomU64ForInit() {
+} // Anonymous namespace
+
+u64 KSystemControl::GenerateRandomU64() {
static std::random_device device;
static std::mt19937 gen(device());
static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
return distribution(gen);
}
-} // Anonymous namespace
-u64 GenerateRandomRange(u64 min, u64 max) {
- return GenerateUniformRange(min, max, GenerateRandomU64ForInit);
+u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
+ return GenerateUniformRange(min, max, GenerateRandomU64);
}
-} // namespace Kernel::Memory::SystemControl
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_system_control.h b/src/core/hle/kernel/k_system_control.h
new file mode 100644
index 000000000..1d5b64ffa
--- /dev/null
+++ b/src/core/hle/kernel/k_system_control.h
@@ -0,0 +1,19 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Kernel {
+
+class KSystemControl {
+public:
+ KSystemControl() = default;
+
+ static u64 GenerateRandomRange(u64 min, u64 max);
+ static u64 GenerateRandomU64();
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index b59259c4f..1661afbd9 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -18,16 +18,15 @@
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/hardware_properties.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_condition_variable.h"
+#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory/memory_layout.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_results.h"
@@ -127,7 +126,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
// Set core ID and wait result.
core_id = phys_core;
- wait_result = Svc::ResultNoSynchronizationObject;
+ wait_result = ResultNoSynchronizationObject;
// Set priorities.
priority = prio;
@@ -238,7 +237,7 @@ void KThread::Finalize() {
while (it != waiter_list.end()) {
// The thread shouldn't be a kernel waiter.
it->SetLockOwner(nullptr);
- it->SetSyncedObject(nullptr, Svc::ResultInvalidState);
+ it->SetSyncedObject(nullptr, ResultInvalidState);
it->Wakeup();
it = waiter_list.erase(it);
}
@@ -447,7 +446,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
// If the core id is no-update magic, preserve the ideal core id.
if (core_id == Svc::IdealCoreNoUpdate) {
core_id = virtual_ideal_core_id;
- R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, Svc::ResultInvalidCombination);
+ R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, ResultInvalidCombination);
}
// Set the virtual core/affinity mask.
@@ -526,7 +525,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
if (GetStackParameters().is_pinned) {
// Verify that the current thread isn't terminating.
R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
- Svc::ResultTerminationRequested);
+ ResultTerminationRequested);
// Note that the thread was pinned.
thread_is_pinned = true;
@@ -604,7 +603,7 @@ void KThread::WaitCancel() {
sleeping_queue->WakeupThread(this);
wait_cancelled = true;
} else {
- SetSyncedObject(nullptr, Svc::ResultCancelled);
+ SetSyncedObject(nullptr, ResultCancelled);
SetState(ThreadState::Runnable);
wait_cancelled = false;
}
@@ -663,12 +662,12 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
// Verify our state.
const auto cur_state = GetState();
R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable),
- Svc::ResultInvalidState);
+ ResultInvalidState);
// Either pause or resume.
if (activity == Svc::ThreadActivity::Paused) {
// Verify that we're not suspended.
- R_UNLESS(!IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState);
+ R_UNLESS(!IsSuspendRequested(SuspendType::Thread), ResultInvalidState);
// Suspend.
RequestSuspend(SuspendType::Thread);
@@ -676,7 +675,7 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
ASSERT(activity == Svc::ThreadActivity::Runnable);
// Verify that we're suspended.
- R_UNLESS(IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState);
+ R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState);
// Resume.
Resume(SuspendType::Thread);
@@ -698,7 +697,7 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
if (GetStackParameters().is_pinned) {
// Verify that the current thread isn't terminating.
R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
- Svc::ResultTerminationRequested);
+ ResultTerminationRequested);
// Note that the thread was pinned and not current.
thread_is_pinned = true;
@@ -745,7 +744,7 @@ ResultCode KThread::GetThreadContext3(std::vector<u8>& out) {
KScopedSchedulerLock sl{kernel};
// Verify that we're suspended.
- R_UNLESS(IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState);
+ R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState);
// If we're not terminating, get the thread's user context.
if (!IsTerminationRequested()) {
@@ -783,7 +782,7 @@ void KThread::AddWaiterImpl(KThread* thread) {
}
// Keep track of how many kernel waiters we have.
- if (Memory::IsKernelAddressKey(thread->GetAddressKey())) {
+ if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters++) >= 0);
}
@@ -796,7 +795,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
// Keep track of how many kernel waiters we have.
- if (Memory::IsKernelAddressKey(thread->GetAddressKey())) {
+ if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters--) > 0);
}
@@ -871,7 +870,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
KThread* thread = std::addressof(*it);
// Keep track of how many kernel waiters we have.
- if (Memory::IsKernelAddressKey(thread->GetAddressKey())) {
+ if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters--) > 0);
}
it = waiter_list.erase(it);
@@ -905,12 +904,11 @@ ResultCode KThread::Run() {
KScopedSchedulerLock lk{kernel};
// If either this thread or the current thread are requesting termination, note it.
- R_UNLESS(!IsTerminationRequested(), Svc::ResultTerminationRequested);
- R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
- Svc::ResultTerminationRequested);
+ R_UNLESS(!IsTerminationRequested(), ResultTerminationRequested);
+ R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
// Ensure our thread state is correct.
- R_UNLESS(GetState() == ThreadState::Initialized, Svc::ResultInvalidState);
+ R_UNLESS(GetState() == ThreadState::Initialized, ResultInvalidState);
// If the current thread has been asked to suspend, suspend it and retry.
if (GetCurrentThread(kernel).IsSuspended()) {
@@ -962,7 +960,7 @@ ResultCode KThread::Sleep(s64 timeout) {
// Check if the thread should terminate.
if (IsTerminationRequested()) {
slp.CancelSleep();
- return Svc::ResultTerminationRequested;
+ return ResultTerminationRequested;
}
// Mark the thread as waiting.
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b20c2d13a..331cf3a60 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -26,19 +26,19 @@
#include "core/device_memory.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/k_slab_heap.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory/memory_layout.h"
-#include "core/hle/kernel/memory/memory_manager.h"
-#include "core/hle/kernel/memory/slab_heap.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/service_thread.h"
-#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
@@ -101,8 +101,6 @@ struct KernelCore::Impl {
current_process = nullptr;
- system_resource_limit = nullptr;
-
global_handle_table.Clear();
preemption_event = nullptr;
@@ -111,6 +109,13 @@ struct KernelCore::Impl {
exclusive_monitor.reset();
+ hid_shared_mem = nullptr;
+ font_shared_mem = nullptr;
+ irs_shared_mem = nullptr;
+ time_shared_mem = nullptr;
+
+ system_resource_limit = nullptr;
+
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
}
@@ -141,11 +146,17 @@ struct KernelCore::Impl {
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
.IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 900).IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 933).IsSuccess());
- if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 0x60000)) {
+ // Derived from recent software updates. The kernel reserves 27MB
+ constexpr u64 kernel_size{0x1b00000};
+ if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) {
UNREACHABLE();
}
+ // Reserve secure applet memory, introduced in firmware 5.0.0
+ constexpr u64 secure_applet_memory_size{0x400000};
+ ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
+ secure_applet_memory_size));
}
void InitializePreemption(KernelCore& kernel) {
@@ -260,7 +271,7 @@ struct KernelCore::Impl {
void InitializeMemoryLayout() {
// Initialize memory layout
- constexpr Memory::MemoryLayout layout{Memory::MemoryLayout::GetDefaultLayout()};
+ constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()};
constexpr std::size_t hid_size{0x40000};
constexpr std::size_t font_size{0x1100000};
constexpr std::size_t irs_size{0x8000};
@@ -271,39 +282,42 @@ struct KernelCore::Impl {
constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
// Initialize memory manager
- memory_manager = std::make_unique<Memory::MemoryManager>();
- memory_manager->InitializeManager(Memory::MemoryManager::Pool::Application,
+ memory_manager = std::make_unique<KMemoryManager>();
+ memory_manager->InitializeManager(KMemoryManager::Pool::Application,
layout.Application().StartAddress(),
layout.Application().EndAddress());
- memory_manager->InitializeManager(Memory::MemoryManager::Pool::Applet,
+ memory_manager->InitializeManager(KMemoryManager::Pool::Applet,
layout.Applet().StartAddress(),
layout.Applet().EndAddress());
- memory_manager->InitializeManager(Memory::MemoryManager::Pool::System,
+ memory_manager->InitializeManager(KMemoryManager::Pool::System,
layout.System().StartAddress(),
layout.System().EndAddress());
- hid_shared_mem = Kernel::SharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr,
- {hid_addr, hid_size / Memory::PageSize}, Memory::MemoryPermission::None,
- Memory::MemoryPermission::Read, hid_addr, hid_size, "HID:SharedMemory");
- font_shared_mem = Kernel::SharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr,
- {font_pa, font_size / Memory::PageSize}, Memory::MemoryPermission::None,
- Memory::MemoryPermission::Read, font_pa, font_size, "Font:SharedMemory");
- irs_shared_mem = Kernel::SharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr,
- {irs_addr, irs_size / Memory::PageSize}, Memory::MemoryPermission::None,
- Memory::MemoryPermission::Read, irs_addr, irs_size, "IRS:SharedMemory");
- time_shared_mem = Kernel::SharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr,
- {time_addr, time_size / Memory::PageSize}, Memory::MemoryPermission::None,
- Memory::MemoryPermission::Read, time_addr, time_size, "Time:SharedMemory");
+ hid_shared_mem = Kernel::KSharedMemory::Create(
+ system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size,
+ "HID:SharedMemory");
+ font_shared_mem = Kernel::KSharedMemory::Create(
+ system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size,
+ "Font:SharedMemory");
+ irs_shared_mem = Kernel::KSharedMemory::Create(
+ system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size,
+ "IRS:SharedMemory");
+ time_shared_mem = Kernel::KSharedMemory::Create(
+ system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size,
+ "Time:SharedMemory");
// Allocate slab heaps
- user_slab_heap_pages = std::make_unique<Memory::SlabHeap<Memory::Page>>();
+ user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
+ constexpr u64 user_slab_heap_size{0x1ef000};
+ // Reserve slab heaps
+ ASSERT(
+ system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));
// Initialize slab heaps
- constexpr u64 user_slab_heap_size{0x3de000};
user_slab_heap_pages->Initialize(
system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase),
user_slab_heap_size);
@@ -339,14 +353,14 @@ struct KernelCore::Impl {
std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
// Kernel memory management
- std::unique_ptr<Memory::MemoryManager> memory_manager;
- std::unique_ptr<Memory::SlabHeap<Memory::Page>> user_slab_heap_pages;
+ std::unique_ptr<KMemoryManager> memory_manager;
+ std::unique_ptr<KSlabHeap<Page>> user_slab_heap_pages;
// Shared memory for services
- std::shared_ptr<Kernel::SharedMemory> hid_shared_mem;
- std::shared_ptr<Kernel::SharedMemory> font_shared_mem;
- std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
- std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
+ std::shared_ptr<Kernel::KSharedMemory> hid_shared_mem;
+ std::shared_ptr<Kernel::KSharedMemory> font_shared_mem;
+ std::shared_ptr<Kernel::KSharedMemory> irs_shared_mem;
+ std::shared_ptr<Kernel::KSharedMemory> time_shared_mem;
// Threads used for services
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
@@ -564,51 +578,51 @@ KThread* KernelCore::GetCurrentEmuThread() const {
return impl->GetCurrentEmuThread();
}
-Memory::MemoryManager& KernelCore::MemoryManager() {
+KMemoryManager& KernelCore::MemoryManager() {
return *impl->memory_manager;
}
-const Memory::MemoryManager& KernelCore::MemoryManager() const {
+const KMemoryManager& KernelCore::MemoryManager() const {
return *impl->memory_manager;
}
-Memory::SlabHeap<Memory::Page>& KernelCore::GetUserSlabHeapPages() {
+KSlabHeap<Page>& KernelCore::GetUserSlabHeapPages() {
return *impl->user_slab_heap_pages;
}
-const Memory::SlabHeap<Memory::Page>& KernelCore::GetUserSlabHeapPages() const {
+const KSlabHeap<Page>& KernelCore::GetUserSlabHeapPages() const {
return *impl->user_slab_heap_pages;
}
-Kernel::SharedMemory& KernelCore::GetHidSharedMem() {
+Kernel::KSharedMemory& KernelCore::GetHidSharedMem() {
return *impl->hid_shared_mem;
}
-const Kernel::SharedMemory& KernelCore::GetHidSharedMem() const {
+const Kernel::KSharedMemory& KernelCore::GetHidSharedMem() const {
return *impl->hid_shared_mem;
}
-Kernel::SharedMemory& KernelCore::GetFontSharedMem() {
+Kernel::KSharedMemory& KernelCore::GetFontSharedMem() {
return *impl->font_shared_mem;
}
-const Kernel::SharedMemory& KernelCore::GetFontSharedMem() const {
+const Kernel::KSharedMemory& KernelCore::GetFontSharedMem() const {
return *impl->font_shared_mem;
}
-Kernel::SharedMemory& KernelCore::GetIrsSharedMem() {
+Kernel::KSharedMemory& KernelCore::GetIrsSharedMem() {
return *impl->irs_shared_mem;
}
-const Kernel::SharedMemory& KernelCore::GetIrsSharedMem() const {
+const Kernel::KSharedMemory& KernelCore::GetIrsSharedMem() const {
return *impl->irs_shared_mem;
}
-Kernel::SharedMemory& KernelCore::GetTimeSharedMem() {
+Kernel::KSharedMemory& KernelCore::GetTimeSharedMem() {
return *impl->time_shared_mem;
}
-const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const {
+const Kernel::KSharedMemory& KernelCore::GetTimeSharedMem() const {
return *impl->time_shared_mem;
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 806a0d986..56906f2da 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,7 +11,7 @@
#include <vector>
#include "core/arm/cpu_interrupt_handler.h"
#include "core/hardware_properties.h"
-#include "core/hle/kernel/memory/memory_types.h"
+#include "core/hle/kernel/memory_types.h"
#include "core/hle/kernel/object.h"
namespace Core {
@@ -27,25 +27,23 @@ struct EventType;
namespace Kernel {
-namespace Memory {
-class MemoryManager;
-template <typename T>
-class SlabHeap;
-} // namespace Memory
-
class ClientPort;
class GlobalSchedulerContext;
class HandleTable;
-class PhysicalCore;
-class Process;
+class KMemoryManager;
class KResourceLimit;
class KScheduler;
-class SharedMemory;
+class KSharedMemory;
+class KThread;
+class PhysicalCore;
+class Process;
class ServiceThread;
class Synchronization;
-class KThread;
class TimeManager;
+template <typename T>
+class KSlabHeap;
+
using EmuThreadHandle = uintptr_t;
constexpr EmuThreadHandle EmuThreadHandleInvalid{};
constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
@@ -178,40 +176,40 @@ public:
void RegisterHostThread();
/// Gets the virtual memory manager for the kernel.
- Memory::MemoryManager& MemoryManager();
+ KMemoryManager& MemoryManager();
/// Gets the virtual memory manager for the kernel.
- const Memory::MemoryManager& MemoryManager() const;
+ const KMemoryManager& MemoryManager() const;
/// Gets the slab heap allocated for user space pages.
- Memory::SlabHeap<Memory::Page>& GetUserSlabHeapPages();
+ KSlabHeap<Page>& GetUserSlabHeapPages();
/// Gets the slab heap allocated for user space pages.
- const Memory::SlabHeap<Memory::Page>& GetUserSlabHeapPages() const;
+ const KSlabHeap<Page>& GetUserSlabHeapPages() const;
/// Gets the shared memory object for HID services.
- Kernel::SharedMemory& GetHidSharedMem();
+ Kernel::KSharedMemory& GetHidSharedMem();
/// Gets the shared memory object for HID services.
- const Kernel::SharedMemory& GetHidSharedMem() const;
+ const Kernel::KSharedMemory& GetHidSharedMem() const;
/// Gets the shared memory object for font services.
- Kernel::SharedMemory& GetFontSharedMem();
+ Kernel::KSharedMemory& GetFontSharedMem();
/// Gets the shared memory object for font services.
- const Kernel::SharedMemory& GetFontSharedMem() const;
+ const Kernel::KSharedMemory& GetFontSharedMem() const;
/// Gets the shared memory object for IRS services.
- Kernel::SharedMemory& GetIrsSharedMem();
+ Kernel::KSharedMemory& GetIrsSharedMem();
/// Gets the shared memory object for IRS services.
- const Kernel::SharedMemory& GetIrsSharedMem() const;
+ const Kernel::KSharedMemory& GetIrsSharedMem() const;
/// Gets the shared memory object for Time services.
- Kernel::SharedMemory& GetTimeSharedMem();
+ Kernel::KSharedMemory& GetTimeSharedMem();
/// Gets the shared memory object for Time services.
- const Kernel::SharedMemory& GetTimeSharedMem() const;
+ const Kernel::KSharedMemory& GetTimeSharedMem() const;
/// Suspend/unsuspend the OS.
void Suspend(bool in_suspention);
diff --git a/src/core/hle/kernel/memory/page_heap.h b/src/core/hle/kernel/memory/page_heap.h
deleted file mode 100644
index 131093284..000000000
--- a/src/core/hle/kernel/memory/page_heap.h
+++ /dev/null
@@ -1,370 +0,0 @@
-// Copyright 2020 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
-#pragma once
-
-#include <array>
-#include <bit>
-#include <vector>
-
-#include "common/alignment.h"
-#include "common/assert.h"
-#include "common/common_funcs.h"
-#include "common/common_types.h"
-#include "core/hle/kernel/memory/memory_types.h"
-
-namespace Kernel::Memory {
-
-class PageHeap final : NonCopyable {
-public:
- static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) {
- const auto target_pages{std::max(num_pages, align_pages)};
- for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) {
- if (target_pages <=
- (static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
- return static_cast<s32>(i);
- }
- }
- return -1;
- }
-
- static constexpr s32 GetBlockIndex(std::size_t num_pages) {
- for (s32 i{static_cast<s32>(NumMemoryBlockPageShifts) - 1}; i >= 0; i--) {
- if (num_pages >= (static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
- return i;
- }
- }
- return -1;
- }
-
- static constexpr std::size_t GetBlockSize(std::size_t index) {
- return static_cast<std::size_t>(1) << MemoryBlockPageShifts[index];
- }
-
- static constexpr std::size_t GetBlockNumPages(std::size_t index) {
- return GetBlockSize(index) / PageSize;
- }
-
-private:
- static constexpr std::size_t NumMemoryBlockPageShifts{7};
- static constexpr std::array<std::size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
- 0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E,
- };
-
- class Block final : NonCopyable {
- private:
- class Bitmap final : NonCopyable {
- public:
- static constexpr std::size_t MaxDepth{4};
-
- private:
- std::array<u64*, MaxDepth> bit_storages{};
- std::size_t num_bits{};
- std::size_t used_depths{};
-
- public:
- constexpr Bitmap() = default;
-
- constexpr std::size_t GetNumBits() const {
- return num_bits;
- }
- constexpr s32 GetHighestDepthIndex() const {
- return static_cast<s32>(used_depths) - 1;
- }
-
- constexpr u64* Initialize(u64* storage, std::size_t size) {
- //* Initially, everything is un-set
- num_bits = 0;
-
- // Calculate the needed bitmap depth
- used_depths = static_cast<std::size_t>(GetRequiredDepth(size));
- ASSERT(used_depths <= MaxDepth);
-
- // Set the bitmap pointers
- for (s32 depth{GetHighestDepthIndex()}; depth >= 0; depth--) {
- bit_storages[depth] = storage;
- size = Common::AlignUp(size, 64) / 64;
- storage += size;
- }
-
- return storage;
- }
-
- s64 FindFreeBlock() const {
- uintptr_t offset{};
- s32 depth{};
-
- do {
- const u64 v{bit_storages[depth][offset]};
- if (v == 0) {
- // Non-zero depth indicates that a previous level had a free block
- ASSERT(depth == 0);
- return -1;
- }
- offset = offset * 64 + static_cast<u32>(std::countr_zero(v));
- ++depth;
- } while (depth < static_cast<s32>(used_depths));
-
- return static_cast<s64>(offset);
- }
-
- constexpr void SetBit(std::size_t offset) {
- SetBit(GetHighestDepthIndex(), offset);
- num_bits++;
- }
-
- constexpr void ClearBit(std::size_t offset) {
- ClearBit(GetHighestDepthIndex(), offset);
- num_bits--;
- }
-
- constexpr bool ClearRange(std::size_t offset, std::size_t count) {
- const s32 depth{GetHighestDepthIndex()};
- const auto bit_ind{offset / 64};
- u64* bits{bit_storages[depth]};
- if (count < 64) {
- const auto shift{offset % 64};
- ASSERT(shift + count <= 64);
- // Check that all the bits are set
- const u64 mask{((1ULL << count) - 1) << shift};
- u64 v{bits[bit_ind]};
- if ((v & mask) != mask) {
- return false;
- }
-
- // Clear the bits
- v &= ~mask;
- bits[bit_ind] = v;
- if (v == 0) {
- ClearBit(depth - 1, bit_ind);
- }
- } else {
- ASSERT(offset % 64 == 0);
- ASSERT(count % 64 == 0);
- // Check that all the bits are set
- std::size_t remaining{count};
- std::size_t i = 0;
- do {
- if (bits[bit_ind + i++] != ~u64(0)) {
- return false;
- }
- remaining -= 64;
- } while (remaining > 0);
-
- // Clear the bits
- remaining = count;
- i = 0;
- do {
- bits[bit_ind + i] = 0;
- ClearBit(depth - 1, bit_ind + i);
- i++;
- remaining -= 64;
- } while (remaining > 0);
- }
-
- num_bits -= count;
- return true;
- }
-
- private:
- constexpr void SetBit(s32 depth, std::size_t offset) {
- while (depth >= 0) {
- const auto ind{offset / 64};
- const auto which{offset % 64};
- const u64 mask{1ULL << which};
-
- u64* bit{std::addressof(bit_storages[depth][ind])};
- const u64 v{*bit};
- ASSERT((v & mask) == 0);
- *bit = v | mask;
- if (v) {
- break;
- }
- offset = ind;
- depth--;
- }
- }
-
- constexpr void ClearBit(s32 depth, std::size_t offset) {
- while (depth >= 0) {
- const auto ind{offset / 64};
- const auto which{offset % 64};
- const u64 mask{1ULL << which};
-
- u64* bit{std::addressof(bit_storages[depth][ind])};
- u64 v{*bit};
- ASSERT((v & mask) != 0);
- v &= ~mask;
- *bit = v;
- if (v) {
- break;
- }
- offset = ind;
- depth--;
- }
- }
-
- private:
- static constexpr s32 GetRequiredDepth(std::size_t region_size) {
- s32 depth = 0;
- while (true) {
- region_size /= 64;
- depth++;
- if (region_size == 0) {
- return depth;
- }
- }
- }
-
- public:
- static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size) {
- std::size_t overhead_bits = 0;
- for (s32 depth{GetRequiredDepth(region_size) - 1}; depth >= 0; depth--) {
- region_size = Common::AlignUp(region_size, 64) / 64;
- overhead_bits += region_size;
- }
- return overhead_bits * sizeof(u64);
- }
- };
-
- private:
- Bitmap bitmap;
- VAddr heap_address{};
- uintptr_t end_offset{};
- std::size_t block_shift{};
- std::size_t next_block_shift{};
-
- public:
- constexpr Block() = default;
-
- constexpr std::size_t GetShift() const {
- return block_shift;
- }
- constexpr std::size_t GetNextShift() const {
- return next_block_shift;
- }
- constexpr std::size_t GetSize() const {
- return static_cast<std::size_t>(1) << GetShift();
- }
- constexpr std::size_t GetNumPages() const {
- return GetSize() / PageSize;
- }
- constexpr std::size_t GetNumFreeBlocks() const {
- return bitmap.GetNumBits();
- }
- constexpr std::size_t GetNumFreePages() const {
- return GetNumFreeBlocks() * GetNumPages();
- }
-
- constexpr u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs,
- u64* bit_storage) {
- // Set shifts
- block_shift = bs;
- next_block_shift = nbs;
-
- // Align up the address
- VAddr end{addr + size};
- const auto align{(next_block_shift != 0) ? (1ULL << next_block_shift)
- : (1ULL << block_shift)};
- addr = Common::AlignDown((addr), align);
- end = Common::AlignUp((end), align);
-
- heap_address = addr;
- end_offset = (end - addr) / (1ULL << block_shift);
- return bitmap.Initialize(bit_storage, end_offset);
- }
-
- constexpr VAddr PushBlock(VAddr address) {
- // Set the bit for the free block
- std::size_t offset{(address - heap_address) >> GetShift()};
- bitmap.SetBit(offset);
-
- // If we have a next shift, try to clear the blocks below and return the address
- if (GetNextShift()) {
- const auto diff{1ULL << (GetNextShift() - GetShift())};
- offset = Common::AlignDown(offset, diff);
- if (bitmap.ClearRange(offset, diff)) {
- return heap_address + (offset << GetShift());
- }
- }
-
- // We couldn't coalesce, or we're already as big as possible
- return 0;
- }
-
- VAddr PopBlock() {
- // Find a free block
- const s64 soffset{bitmap.FindFreeBlock()};
- if (soffset < 0) {
- return 0;
- }
- const auto offset{static_cast<std::size_t>(soffset)};
-
- // Update our tracking and return it
- bitmap.ClearBit(offset);
- return heap_address + (offset << GetShift());
- }
-
- public:
- static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size,
- std::size_t cur_block_shift,
- std::size_t next_block_shift) {
- const auto cur_block_size{(1ULL << cur_block_shift)};
- const auto next_block_size{(1ULL << next_block_shift)};
- const auto align{(next_block_shift != 0) ? next_block_size : cur_block_size};
- return Bitmap::CalculateMetadataOverheadSize(
- (align * 2 + Common::AlignUp(region_size, align)) / cur_block_size);
- }
- };
-
-public:
- PageHeap() = default;
-
- constexpr VAddr GetAddress() const {
- return heap_address;
- }
- constexpr std::size_t GetSize() const {
- return heap_size;
- }
- constexpr VAddr GetEndAddress() const {
- return GetAddress() + GetSize();
- }
- constexpr std::size_t GetPageOffset(VAddr block) const {
- return (block - GetAddress()) / PageSize;
- }
-
- void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size);
- VAddr AllocateBlock(s32 index);
- void Free(VAddr addr, std::size_t num_pages);
-
- void UpdateUsedSize() {
- used_size = heap_size - (GetNumFreePages() * PageSize);
- }
-
- static std::size_t CalculateMetadataOverheadSize(std::size_t region_size);
-
-private:
- constexpr std::size_t GetNumFreePages() const {
- std::size_t num_free{};
-
- for (const auto& block : blocks) {
- num_free += block.GetNumFreePages();
- }
-
- return num_free;
- }
-
- void FreeBlock(VAddr block, s32 index);
-
- VAddr heap_address{};
- std::size_t heap_size{};
- std::size_t used_size{};
- std::array<Block, NumMemoryBlockPageShifts> blocks{};
- std::vector<u64> metadata;
-};
-
-} // namespace Kernel::Memory
diff --git a/src/core/hle/kernel/memory/system_control.h b/src/core/hle/kernel/memory/system_control.h
deleted file mode 100644
index 19cab8cbc..000000000
--- a/src/core/hle/kernel/memory/system_control.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2020 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-
-namespace Kernel::Memory::SystemControl {
-
-u64 GenerateRandomRange(u64 min, u64 max);
-
-} // namespace Kernel::Memory::SystemControl
diff --git a/src/core/hle/kernel/memory/memory_types.h b/src/core/hle/kernel/memory_types.h
index a75bf77c0..d458f0eca 100644
--- a/src/core/hle/kernel/memory/memory_types.h
+++ b/src/core/hle/kernel/memory_types.h
@@ -8,11 +8,11 @@
#include "common/common_types.h"
-namespace Kernel::Memory {
+namespace Kernel {
constexpr std::size_t PageBits{12};
constexpr std::size_t PageSize{1 << PageBits};
using Page = std::array<u8, PageSize>;
-} // namespace Kernel::Memory
+} // namespace Kernel
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 2286b292d..73b85d6f9 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -14,14 +14,14 @@
#include "core/device_memory.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/code_set.h"
-#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/k_memory_block_manager.h"
+#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_slab_heap.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory/memory_block_manager.h"
-#include "core/hle/kernel/memory/page_table.h"
-#include "core/hle/kernel/memory/slab_heap.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/lock.h"
@@ -39,6 +39,7 @@ namespace {
*/
void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
+ ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0,
owner_process.GetIdealCoreId(), stack_top, &owner_process);
@@ -117,6 +118,9 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
std::shared_ptr<Process> process = std::make_shared<Process>(system);
process->name = std::move(name);
+
+ // TODO: This is inaccurate
+ // The process should hold a reference to the kernel-wide resource limit.
process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
process->status = ProcessStatus::Created;
process->program_id = 0;
@@ -155,6 +159,9 @@ void Process::DecrementThreadCount() {
}
u64 Process::GetTotalPhysicalMemoryAvailable() const {
+ // TODO: This is expected to always return the application memory pool size after accurately
+ // reserving kernel resources. The current workaround uses a process-local resource limit of
+ // application memory pool size, which is inaccurate.
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
main_thread_stack_size};
@@ -248,8 +255,8 @@ ResultCode Process::Reset() {
KScopedSchedulerLock sl{kernel};
// Validate that we're in a state that we can reset.
- R_UNLESS(status != ProcessStatus::Exited, Svc::ResultInvalidState);
- R_UNLESS(is_signaled, Svc::ResultInvalidState);
+ R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState);
+ R_UNLESS(is_signaled, ResultInvalidState);
// Clear signaled.
is_signaled = false;
@@ -264,18 +271,29 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
system_resource_size = metadata.GetSystemResourceSize();
image_size = code_size;
+ // Set initial resource limits
+ resource_limit->SetLimitValue(
+ LimitableResource::PhysicalMemory,
+ kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
+ KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
+ code_size + system_resource_size);
+ if (!memory_reservation.Succeeded()) {
+ LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
+ code_size + system_resource_size);
+ return ResultResourceLimitedExceeded;
+ }
// Initialize proces address space
if (const ResultCode result{
page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000,
- code_size, Memory::MemoryManager::Pool::Application)};
+ code_size, KMemoryManager::Pool::Application)};
result.IsError()) {
return result;
}
// Map process code region
- if (const ResultCode result{page_table->MapProcessCode(
- page_table->GetCodeRegionStart(), code_size / Memory::PageSize,
- Memory::MemoryState::Code, Memory::MemoryPermission::None)};
+ if (const ResultCode result{page_table->MapProcessCode(page_table->GetCodeRegionStart(),
+ code_size / PageSize, KMemoryState::Code,
+ KMemoryPermission::None)};
result.IsError()) {
return result;
}
@@ -308,21 +326,24 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
// Set initial resource limits
resource_limit->SetLimitValue(
LimitableResource::PhysicalMemory,
- kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
+ kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
+
resource_limit->SetLimitValue(LimitableResource::Threads, 608);
resource_limit->SetLimitValue(LimitableResource::Events, 700);
resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
- ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemory, code_size));
// Create TLS region
tls_region_address = CreateTLSRegion();
+ memory_reservation.Commit();
return handle_table.SetSize(capabilities.GetHandleTableSize());
}
void Process::Run(s32 main_thread_priority, u64 stack_size) {
AllocateMainThreadStack(stack_size);
+ resource_limit->Reserve(LimitableResource::Threads, 1);
+ resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size};
ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError());
@@ -330,8 +351,6 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
ChangeStatus(ProcessStatus::Running);
SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
- resource_limit->Reserve(LimitableResource::Threads, 1);
- resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
}
void Process::PrepareForTermination() {
@@ -358,6 +377,11 @@ void Process::PrepareForTermination() {
FreeTLSRegion(tls_region_address);
tls_region_address = 0;
+ if (resource_limit) {
+ resource_limit->Release(LimitableResource::PhysicalMemory,
+ main_thread_stack_size + image_size);
+ }
+
ChangeStatus(ProcessStatus::Exited);
}
@@ -381,22 +405,22 @@ VAddr Process::CreateTLSRegion() {
return *tls_page_iter->ReserveSlot();
}
- Memory::Page* const tls_page_ptr{kernel.GetUserSlabHeapPages().Allocate()};
+ Page* const tls_page_ptr{kernel.GetUserSlabHeapPages().Allocate()};
ASSERT(tls_page_ptr);
const VAddr start{page_table->GetKernelMapRegionStart()};
const VAddr size{page_table->GetKernelMapRegionEnd() - start};
const PAddr tls_map_addr{system.DeviceMemory().GetPhysicalAddr(tls_page_ptr)};
- const VAddr tls_page_addr{
- page_table
- ->AllocateAndMapMemory(1, Memory::PageSize, true, start, size / Memory::PageSize,
- Memory::MemoryState::ThreadLocal,
- Memory::MemoryPermission::ReadAndWrite, tls_map_addr)
- .ValueOr(0)};
+ const VAddr tls_page_addr{page_table
+ ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize,
+ KMemoryState::ThreadLocal,
+ KMemoryPermission::ReadAndWrite,
+ tls_map_addr)
+ .ValueOr(0)};
ASSERT(tls_page_addr);
- std::memset(tls_page_ptr, 0, Memory::PageSize);
+ std::memset(tls_page_ptr, 0, PageSize);
tls_pages.emplace_back(tls_page_addr);
const auto reserve_result{tls_pages.back().ReserveSlot()};
@@ -423,15 +447,15 @@ void Process::FreeTLSRegion(VAddr tls_address) {
void Process::LoadModule(CodeSet code_set, VAddr base_addr) {
std::lock_guard lock{HLE::g_hle_lock};
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
- Memory::MemoryPermission permission) {
+ KMemoryPermission permission) {
page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission);
};
system.Memory().WriteBlock(*this, base_addr, code_set.memory.data(), code_set.memory.size());
- ReprotectSegment(code_set.CodeSegment(), Memory::MemoryPermission::ReadAndExecute);
- ReprotectSegment(code_set.RODataSegment(), Memory::MemoryPermission::Read);
- ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite);
+ ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute);
+ ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read);
+ ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite);
}
bool Process::IsSignaled() const {
@@ -440,9 +464,9 @@ bool Process::IsSignaled() const {
}
Process::Process(Core::System& system)
- : KSynchronizationObject{system.Kernel()},
- page_table{std::make_unique<Memory::PageTable>(system)}, handle_table{system.Kernel()},
- address_arbiter{system}, condition_var{system}, state_lock{system.Kernel()}, system{system} {}
+ : KSynchronizationObject{system.Kernel()}, page_table{std::make_unique<KPageTable>(system)},
+ handle_table{system.Kernel()}, address_arbiter{system}, condition_var{system},
+ state_lock{system.Kernel()}, system{system} {}
Process::~Process() = default;
@@ -460,16 +484,15 @@ ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) {
ASSERT(stack_size);
// The kernel always ensures that the given stack size is page aligned.
- main_thread_stack_size = Common::AlignUp(stack_size, Memory::PageSize);
+ main_thread_stack_size = Common::AlignUp(stack_size, PageSize);
const VAddr start{page_table->GetStackRegionStart()};
const std::size_t size{page_table->GetStackRegionEnd() - start};
CASCADE_RESULT(main_thread_stack_top,
page_table->AllocateAndMapMemory(
- main_thread_stack_size / Memory::PageSize, Memory::PageSize, false, start,
- size / Memory::PageSize, Memory::MemoryState::Stack,
- Memory::MemoryPermission::ReadAndWrite));
+ main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize,
+ KMemoryState::Stack, KMemoryPermission::ReadAndWrite));
main_thread_stack_top += main_thread_stack_size;
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 320b0f347..45eefb90e 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -29,16 +29,13 @@ class ProgramMetadata;
namespace Kernel {
class KernelCore;
+class KPageTable;
class KResourceLimit;
class KThread;
class TLSPage;
struct CodeSet;
-namespace Memory {
-class PageTable;
-}
-
enum class MemoryRegion : u16 {
APPLICATION = 1,
SYSTEM = 2,
@@ -104,12 +101,12 @@ public:
}
/// Gets a reference to the process' page table.
- Memory::PageTable& PageTable() {
+ KPageTable& PageTable() {
return *page_table;
}
/// Gets const a reference to the process' page table.
- const Memory::PageTable& PageTable() const {
+ const KPageTable& PageTable() const {
return *page_table;
}
@@ -385,7 +382,7 @@ private:
ResultCode AllocateMainThreadStack(std::size_t stack_size);
/// Memory manager for this process
- std::unique_ptr<Memory::PageTable> page_table;
+ std::unique_ptr<KPageTable> page_table;
/// Current status of the process
ProcessStatus status{};
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp
index 0566311b6..3fc326eab 100644
--- a/src/core/hle/kernel/process_capability.cpp
+++ b/src/core/hle/kernel/process_capability.cpp
@@ -6,10 +6,10 @@
#include "common/bit_util.h"
#include "common/logging/log.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/memory/page_table.h"
+#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/process_capability.h"
+#include "core/hle/kernel/svc_results.h"
namespace Kernel {
namespace {
@@ -69,7 +69,7 @@ u32 GetFlagBitOffset(CapabilityType type) {
ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabilities,
std::size_t num_capabilities,
- Memory::PageTable& page_table) {
+ KPageTable& page_table) {
Clear();
// Allow all cores and priorities.
@@ -82,7 +82,7 @@ ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabiliti
ResultCode ProcessCapabilities::InitializeForUserProcess(const u32* capabilities,
std::size_t num_capabilities,
- Memory::PageTable& page_table) {
+ KPageTable& page_table) {
Clear();
return ParseCapabilities(capabilities, num_capabilities, page_table);
@@ -108,7 +108,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() {
ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities,
std::size_t num_capabilities,
- Memory::PageTable& page_table) {
+ KPageTable& page_table) {
u32 set_flags = 0;
u32 set_svc_bits = 0;
@@ -123,13 +123,13 @@ ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities,
// If there's only one, then there's a problem.
if (i >= num_capabilities) {
LOG_ERROR(Kernel, "Invalid combination! i={}", i);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
const auto size_flags = capabilities[i];
if (GetCapabilityType(size_flags) != CapabilityType::MapPhysical) {
LOG_ERROR(Kernel, "Invalid capability type! size_flags={}", size_flags);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
const auto result = HandleMapPhysicalFlags(descriptor, size_flags, page_table);
@@ -155,11 +155,11 @@ ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities,
}
ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits,
- u32 flag, Memory::PageTable& page_table) {
+ u32 flag, KPageTable& page_table) {
const auto type = GetCapabilityType(flag);
if (type == CapabilityType::Unset) {
- return ERR_INVALID_CAPABILITY_DESCRIPTOR;
+ return ResultInvalidCapabilityDescriptor;
}
// Bail early on ignorable entries, as one would expect,
@@ -176,7 +176,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s
LOG_ERROR(Kernel,
"Attempted to initialize flags that may only be initialized once. set_flags={}",
set_flags);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
set_flags |= set_flag;
@@ -202,7 +202,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s
}
LOG_ERROR(Kernel, "Invalid capability type! type={}", type);
- return ERR_INVALID_CAPABILITY_DESCRIPTOR;
+ return ResultInvalidCapabilityDescriptor;
}
void ProcessCapabilities::Clear() {
@@ -225,7 +225,7 @@ ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
if (priority_mask != 0 || core_mask != 0) {
LOG_ERROR(Kernel, "Core or priority mask are not zero! priority_mask={}, core_mask={}",
priority_mask, core_mask);
- return ERR_INVALID_CAPABILITY_DESCRIPTOR;
+ return ResultInvalidCapabilityDescriptor;
}
const u32 core_num_min = (flags >> 16) & 0xFF;
@@ -233,7 +233,7 @@ ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
if (core_num_min > core_num_max) {
LOG_ERROR(Kernel, "Core min is greater than core max! core_num_min={}, core_num_max={}",
core_num_min, core_num_max);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
const u32 priority_min = (flags >> 10) & 0x3F;
@@ -242,13 +242,13 @@ ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
LOG_ERROR(Kernel,
"Priority min is greater than priority max! priority_min={}, priority_max={}",
core_num_min, priority_max);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
// The switch only has 4 usable cores.
if (core_num_max >= 4) {
LOG_ERROR(Kernel, "Invalid max cores specified! core_num_max={}", core_num_max);
- return ERR_INVALID_PROCESSOR_ID;
+ return ResultInvalidCoreId;
}
const auto make_mask = [](u64 min, u64 max) {
@@ -269,7 +269,7 @@ ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags)
// If we've already set this svc before, bail.
if ((set_svc_bits & svc_bit) != 0) {
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
set_svc_bits |= svc_bit;
@@ -283,7 +283,7 @@ ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags)
if (svc_number >= svc_capabilities.size()) {
LOG_ERROR(Kernel, "Process svc capability is out of range! svc_number={}", svc_number);
- return ERR_OUT_OF_RANGE;
+ return ResultOutOfRange;
}
svc_capabilities[svc_number] = true;
@@ -293,12 +293,12 @@ ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags)
}
ResultCode ProcessCapabilities::HandleMapPhysicalFlags(u32 flags, u32 size_flags,
- Memory::PageTable& page_table) {
+ KPageTable& page_table) {
// TODO(Lioncache): Implement once the memory manager can handle this.
return RESULT_SUCCESS;
}
-ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, Memory::PageTable& page_table) {
+ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, KPageTable& page_table) {
// TODO(Lioncache): Implement once the memory manager can handle this.
return RESULT_SUCCESS;
}
@@ -321,7 +321,7 @@ ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) {
if (interrupt >= interrupt_capabilities.size()) {
LOG_ERROR(Kernel, "Process interrupt capability is out of range! svc_number={}",
interrupt);
- return ERR_OUT_OF_RANGE;
+ return ResultOutOfRange;
}
interrupt_capabilities[interrupt] = true;
@@ -334,7 +334,7 @@ ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) {
const u32 reserved = flags >> 17;
if (reserved != 0) {
LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
- return ERR_RESERVED_VALUE;
+ return ResultReservedValue;
}
program_type = static_cast<ProgramType>((flags >> 14) & 0b111);
@@ -354,7 +354,7 @@ ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) {
LOG_ERROR(Kernel,
"Kernel version is non zero or flags are too small! major_version={}, flags={}",
major_version, flags);
- return ERR_INVALID_CAPABILITY_DESCRIPTOR;
+ return ResultInvalidCapabilityDescriptor;
}
kernel_version = flags;
@@ -365,7 +365,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
const u32 reserved = flags >> 26;
if (reserved != 0) {
LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
- return ERR_RESERVED_VALUE;
+ return ResultReservedValue;
}
handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF);
@@ -376,7 +376,7 @@ ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) {
const u32 reserved = flags >> 19;
if (reserved != 0) {
LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
- return ERR_RESERVED_VALUE;
+ return ResultReservedValue;
}
is_debuggable = (flags & 0x20000) != 0;
diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h
index ea9d12c16..73ad197fa 100644
--- a/src/core/hle/kernel/process_capability.h
+++ b/src/core/hle/kernel/process_capability.h
@@ -12,9 +12,7 @@ union ResultCode;
namespace Kernel {
-namespace Memory {
-class PageTable;
-}
+class KPageTable;
/// The possible types of programs that may be indicated
/// by the program type capability descriptor.
@@ -90,7 +88,7 @@ public:
/// otherwise, an error code upon failure.
///
ResultCode InitializeForKernelProcess(const u32* capabilities, std::size_t num_capabilities,
- Memory::PageTable& page_table);
+ KPageTable& page_table);
/// Initializes this process capabilities instance for a userland process.
///
@@ -103,7 +101,7 @@ public:
/// otherwise, an error code upon failure.
///
ResultCode InitializeForUserProcess(const u32* capabilities, std::size_t num_capabilities,
- Memory::PageTable& page_table);
+ KPageTable& page_table);
/// Initializes this process capabilities instance for a process that does not
/// have any metadata to parse.
@@ -189,7 +187,7 @@ private:
/// @return RESULT_SUCCESS if no errors occur, otherwise an error code.
///
ResultCode ParseCapabilities(const u32* capabilities, std::size_t num_capabilities,
- Memory::PageTable& page_table);
+ KPageTable& page_table);
/// Attempts to parse a capability descriptor that is only represented by a
/// single flag set.
@@ -204,7 +202,7 @@ private:
/// @return RESULT_SUCCESS if no errors occurred, otherwise an error code.
///
ResultCode ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits, u32 flag,
- Memory::PageTable& page_table);
+ KPageTable& page_table);
/// Clears the internal state of this process capability instance. Necessary,
/// to have a sane starting point due to us allowing running executables without
@@ -228,10 +226,10 @@ private:
ResultCode HandleSyscallFlags(u32& set_svc_bits, u32 flags);
/// Handles flags related to mapping physical memory pages.
- ResultCode HandleMapPhysicalFlags(u32 flags, u32 size_flags, Memory::PageTable& page_table);
+ ResultCode HandleMapPhysicalFlags(u32 flags, u32 size_flags, KPageTable& page_table);
/// Handles flags related to mapping IO pages.
- ResultCode HandleMapIOFlags(u32 flags, Memory::PageTable& page_table);
+ ResultCode HandleMapIOFlags(u32 flags, KPageTable& page_table);
/// Handles flags related to the interrupt capability flags.
ResultCode HandleInterruptFlags(u32 flags);
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index fe7a483c4..5d17346ad 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -5,11 +5,11 @@
#include <tuple>
#include "common/assert.h"
#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/svc_results.h"
namespace Kernel {
@@ -18,7 +18,7 @@ ServerPort::~ServerPort() = default;
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
if (pending_sessions.empty()) {
- return ERR_NOT_FOUND;
+ return ResultNotFound;
}
auto session = std::move(pending_sessions.back());
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index 75304b961..8830d4e91 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -4,15 +4,23 @@
#include "common/assert.h"
#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
namespace Kernel {
Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {}
-Session::~Session() = default;
+Session::~Session() {
+ // Release reserved resource when the Session pair was created.
+ kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1);
+}
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
+ // Reserve a new session from the resource limit.
+ KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(),
+ LimitableResource::Sessions);
+ ASSERT(session_reservation.Succeeded());
auto session{std::make_shared<Session>(kernel)};
auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()};
auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()};
@@ -21,6 +29,7 @@ Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
session->client = client_session;
session->server = server_session;
+ session_reservation.Commit();
return std::make_pair(std::move(client_session), std::move(server_session));
}
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
deleted file mode 100644
index 0cd467110..000000000
--- a/src/core/hle/kernel/shared_memory.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/assert.h"
-#include "core/core.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory/page_table.h"
-#include "core/hle/kernel/shared_memory.h"
-
-namespace Kernel {
-
-SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory)
- : Object{kernel}, device_memory{device_memory} {}
-
-SharedMemory::~SharedMemory() = default;
-
-std::shared_ptr<SharedMemory> SharedMemory::Create(
- KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,
- Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission,
- Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size,
- std::string name) {
-
- std::shared_ptr<SharedMemory> shared_memory{
- std::make_shared<SharedMemory>(kernel, device_memory)};
-
- shared_memory->owner_process = owner_process;
- shared_memory->page_list = std::move(page_list);
- shared_memory->owner_permission = owner_permission;
- shared_memory->user_permission = user_permission;
- shared_memory->physical_address = physical_address;
- shared_memory->size = size;
- shared_memory->name = name;
-
- return shared_memory;
-}
-
-ResultCode SharedMemory::Map(Process& target_process, VAddr address, std::size_t size,
- Memory::MemoryPermission permissions) {
- const u64 page_count{(size + Memory::PageSize - 1) / Memory::PageSize};
-
- if (page_list.GetNumPages() != page_count) {
- UNIMPLEMENTED_MSG("Page count does not match");
- }
-
- const Memory::MemoryPermission expected =
- &target_process == owner_process ? owner_permission : user_permission;
-
- if (permissions != expected) {
- UNIMPLEMENTED_MSG("Permission does not match");
- }
-
- return target_process.PageTable().MapPages(address, page_list, Memory::MemoryState::Shared,
- permissions);
-}
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 26650a513..cc8fa6576 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -23,25 +23,25 @@
#include "core/cpu_manager.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_condition_variable.h"
#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_memory_block.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
+#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory/memory_block.h"
-#include "core/hle/kernel/memory/memory_layout.h"
-#include "core/hle/kernel/memory/page_table.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_types.h"
@@ -67,53 +67,53 @@ constexpr bool IsValidAddressRange(VAddr address, u64 size) {
// Helper function that performs the common sanity checks for svcMapMemory
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
// in the same order.
-ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr dst_addr,
- VAddr src_addr, u64 size) {
+ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, VAddr src_addr,
+ u64 size) {
if (!Common::Is4KBAligned(dst_addr)) {
LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(src_addr)) {
LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (size == 0) {
LOG_ERROR(Kernel_SVC, "Size is 0");
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!IsValidAddressRange(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
dst_addr, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (!IsValidAddressRange(src_addr, size)) {
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
src_addr, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (!manager.IsInsideAddressSpace(src_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
src_addr, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (manager.IsOutsideStackRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
dst_addr, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
if (manager.IsInsideHeapRegion(dst_addr, size)) {
@@ -121,7 +121,7 @@ ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr ds
"Destination does not fit within the heap region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
if (manager.IsInsideAliasRegion(dst_addr, size)) {
@@ -129,7 +129,7 @@ ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr ds
"Destination does not fit within the map region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
return RESULT_SUCCESS;
@@ -138,6 +138,7 @@ ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr ds
enum class ResourceLimitValueType {
CurrentValue,
LimitValue,
+ PeakValue,
};
ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
@@ -146,7 +147,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
const auto type = static_cast<LimitableResource>(resource_type);
if (!IsValidResourceType(type)) {
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
- return ERR_INVALID_ENUM_VALUE;
+ return ResultInvalidEnumValue;
}
const auto* const current_process = system.Kernel().CurrentProcess();
@@ -157,14 +158,20 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
if (!resource_limit_object) {
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
resource_limit);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
- if (value_type == ResourceLimitValueType::CurrentValue) {
+ switch (value_type) {
+ case ResourceLimitValueType::CurrentValue:
return MakeResult(resource_limit_object->GetCurrentValue(type));
+ case ResourceLimitValueType::LimitValue:
+ return MakeResult(resource_limit_object->GetLimitValue(type));
+ case ResourceLimitValueType::PeakValue:
+ return MakeResult(resource_limit_object->GetPeakValue(type));
+ default:
+ LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type);
+ return ResultInvalidEnumValue;
}
-
- return MakeResult(resource_limit_object->GetLimitValue(type));
}
} // Anonymous namespace
@@ -177,12 +184,12 @@ static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_s
if ((heap_size % 0x200000) != 0) {
LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}",
heap_size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (heap_size >= 0x200000000) {
LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
@@ -208,34 +215,34 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si
if (!Common::Is4KBAligned(address)) {
LOG_ERROR(Kernel_SVC, "Address not page aligned (0x{:016X})", address);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (size == 0 || !Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Invalid size (0x{:X}). Size must be non-zero and page aligned.",
size);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!IsValidAddressRange(address, size)) {
LOG_ERROR(Kernel_SVC, "Address range overflowed (Address: 0x{:016X}, Size: 0x{:016X})",
address, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
- const auto attributes{static_cast<Memory::MemoryAttribute>(mask | attribute)};
- if (attributes != static_cast<Memory::MemoryAttribute>(mask) ||
- (attributes | Memory::MemoryAttribute::Uncached) != Memory::MemoryAttribute::Uncached) {
+ const auto attributes{static_cast<MemoryAttribute>(mask | attribute)};
+ if (attributes != static_cast<MemoryAttribute>(mask) ||
+ (attributes | MemoryAttribute::Uncached) != MemoryAttribute::Uncached) {
LOG_ERROR(Kernel_SVC,
"Memory attribute doesn't match the given mask (Attribute: 0x{:X}, Mask: {:X}",
attribute, mask);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
- return page_table.SetMemoryAttribute(address, size, static_cast<Memory::MemoryAttribute>(mask),
- static_cast<Memory::MemoryAttribute>(attribute));
+ return page_table.SetMemoryAttribute(address, size, static_cast<KMemoryAttribute>(mask),
+ static_cast<KMemoryAttribute>(attribute));
}
static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask,
@@ -293,7 +300,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
LOG_ERROR(Kernel_SVC,
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
port_name_address);
- return ERR_NOT_FOUND;
+ return ResultNotFound;
}
static constexpr std::size_t PortNameMaxLength = 11;
@@ -302,7 +309,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
if (port_name.size() > PortNameMaxLength) {
LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
port_name.size());
- return ERR_OUT_OF_RANGE;
+ return ResultOutOfRange;
}
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
@@ -311,11 +318,9 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
const auto it = kernel.FindNamedPort(port_name);
if (!kernel.IsValidNamedPort(it)) {
LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
- return ERR_NOT_FOUND;
+ return ResultNotFound;
}
- ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::Sessions, 1));
-
auto client_port = it->second;
std::shared_ptr<ClientSession> client_session;
@@ -340,7 +345,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle);
if (!session) {
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
@@ -405,7 +410,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
const Process* const owner_process = thread->GetOwnerProcess();
if (!owner_process) {
LOG_ERROR(Kernel_SVC, "Non-existent owning process encountered.");
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
*process_id = owner_process->GetProcessID();
@@ -415,7 +420,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
// NOTE: This should also handle debug objects before returning.
LOG_ERROR(Kernel_SVC, "Handle does not exist, handle=0x{:08X}", handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high,
@@ -438,7 +443,7 @@ static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr ha
LOG_ERROR(Kernel_SVC,
"Handle address is not a valid virtual address, handle_address=0x{:016X}",
handles_address);
- return ERR_INVALID_POINTER;
+ return ResultInvalidPointer;
}
static constexpr u64 MaxHandles = 0x40;
@@ -446,7 +451,7 @@ static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr ha
if (handle_count > MaxHandles) {
LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
MaxHandles, handle_count);
- return ERR_OUT_OF_RANGE;
+ return ResultOutOfRange;
}
auto& kernel = system.Kernel();
@@ -459,7 +464,7 @@ static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr ha
if (object == nullptr) {
LOG_ERROR(Kernel_SVC, "Object is a nullptr");
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
objects[i] = object.get();
@@ -481,6 +486,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
+
if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
@@ -502,7 +508,7 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd
thread_handle, address, tag);
// Validate the input address.
- if (Memory::IsKernelAddress(address)) {
+ if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
address);
return ResultInvalidCurrentMemory;
@@ -525,7 +531,7 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) {
LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
// Validate the input address.
- if (Memory::IsKernelAddress(address)) {
+ if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC,
"Attempting to arbitrate an unlock on a kernel address (address={:08X})",
address);
@@ -735,7 +741,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
if (info_sub_id != 0) {
LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
info_sub_id);
- return ERR_INVALID_ENUM_VALUE;
+ return ResultInvalidEnumValue;
}
const auto& current_process_handle_table =
@@ -744,7 +750,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
if (!process) {
LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}",
info_id, info_sub_id, handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
switch (info_id_type) {
@@ -826,7 +832,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
}
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
- return ERR_INVALID_ENUM_VALUE;
+ return ResultInvalidEnumValue;
}
case GetInfoType::IsCurrentProcessBeingDebugged:
@@ -836,13 +842,13 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
case GetInfoType::RegisterResourceLimit: {
if (handle != 0) {
LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
if (info_sub_id != 0) {
LOG_ERROR(Kernel, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
info_sub_id);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
Process* const current_process = system.Kernel().CurrentProcess();
@@ -867,13 +873,13 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
if (handle != 0) {
LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
Process::RANDOM_ENTROPY_SIZE, info_sub_id);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
*result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id);
@@ -890,7 +896,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
info_sub_id);
- return ERR_INVALID_COMBINATION;
+ return ResultInvalidCombination;
}
const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>(
@@ -898,7 +904,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
const auto& core_timing = system.CoreTiming();
@@ -922,7 +928,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
default:
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
- return ERR_INVALID_ENUM_VALUE;
+ return ResultInvalidEnumValue;
}
}
@@ -945,22 +951,22 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
if (!Common::Is4KBAligned(addr)) {
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (size == 0) {
LOG_ERROR(Kernel_SVC, "Size is zero");
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!(addr < addr + size)) {
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
Process* const current_process{system.Kernel().CurrentProcess()};
@@ -968,21 +974,21 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
if (current_process->GetSystemResourceSize() == 0) {
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
- return ERR_INVALID_STATE;
+ return ResultInvalidState;
}
if (!page_table.IsInsideAddressSpace(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
return page_table.MapPhysicalMemory(addr, size);
@@ -999,22 +1005,22 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
if (!Common::Is4KBAligned(addr)) {
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (size == 0) {
LOG_ERROR(Kernel_SVC, "Size is zero");
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!(addr < addr + size)) {
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
Process* const current_process{system.Kernel().CurrentProcess()};
@@ -1022,21 +1028,21 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
if (current_process->GetSystemResourceSize() == 0) {
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
- return ERR_INVALID_STATE;
+ return ResultInvalidState;
}
if (!page_table.IsInsideAddressSpace(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
return page_table.UnmapPhysicalMemory(addr, size);
@@ -1206,31 +1212,30 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han
if (!Common::Is4KBAligned(addr)) {
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (size == 0) {
LOG_ERROR(Kernel_SVC, "Size is 0");
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!IsValidAddressRange(addr, size)) {
LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
addr, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
- const auto permission_type = static_cast<Memory::MemoryPermission>(permissions);
- if ((permission_type | Memory::MemoryPermission::Write) !=
- Memory::MemoryPermission::ReadAndWrite) {
+ const auto permission_type = static_cast<MemoryPermission>(permissions);
+ if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) {
LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
permissions);
- return ERR_INVALID_MEMORY_PERMISSIONS;
+ return ResultInvalidMemoryPermissions;
}
auto* const current_process{system.Kernel().CurrentProcess()};
@@ -1241,7 +1246,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han
"Addr does not fit within the valid region, addr=0x{:016X}, "
"size=0x{:016X}",
addr, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
if (page_table.IsInsideHeapRegion(addr, size)) {
@@ -1249,7 +1254,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han
"Addr does not fit within the heap region, addr=0x{:016X}, "
"size=0x{:016X}",
addr, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
if (page_table.IsInsideAliasRegion(addr, size)) {
@@ -1257,17 +1262,18 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han
"Address does not fit within the map region, addr=0x{:016X}, "
"size=0x{:016X}",
addr, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
- auto shared_memory{current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle)};
+ auto shared_memory{current_process->GetHandleTable().Get<KSharedMemory>(shared_memory_handle)};
if (!shared_memory) {
LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
shared_memory_handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
- return shared_memory->Map(*current_process, addr, size, permission_type);
+ return shared_memory->Map(*current_process, addr, size,
+ static_cast<KMemoryPermission>(permission_type));
}
static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr,
@@ -1285,7 +1291,7 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
if (!process) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
process_handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
auto& memory{system.Memory()};
@@ -1332,18 +1338,18 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
if (!Common::Is4KBAligned(src_address)) {
LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
src_address);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(dst_address)) {
LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
dst_address);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (size == 0 || !Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!IsValidAddressRange(dst_address, size)) {
@@ -1351,7 +1357,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
"Destination address range overflows the address space (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (!IsValidAddressRange(src_address, size)) {
@@ -1359,7 +1365,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
"Source address range overflows the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
@@ -1367,7 +1373,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
if (!process) {
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
process_handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
auto& page_table = process->PageTable();
@@ -1376,7 +1382,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
"Source address range is not within the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (!page_table.IsInsideASLRRegion(dst_address, size)) {
@@ -1384,7 +1390,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
return page_table.MapProcessCodeMemory(dst_address, src_address, size);
@@ -1400,18 +1406,18 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
if (!Common::Is4KBAligned(dst_address)) {
LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
dst_address);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(src_address)) {
LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
src_address);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (size == 0 || Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
- return ERR_INVALID_SIZE;
+ return ResultInvalidSize;
}
if (!IsValidAddressRange(dst_address, size)) {
@@ -1419,7 +1425,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
"Destination address range overflows the address space (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (!IsValidAddressRange(src_address, size)) {
@@ -1427,7 +1433,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
"Source address range overflows the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
@@ -1435,7 +1441,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
if (!process) {
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
process_handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
auto& page_table = process->PageTable();
@@ -1444,7 +1450,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
"Source address range is not within the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
if (!page_table.IsInsideASLRRegion(dst_address, size)) {
@@ -1452,7 +1458,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
- return ERR_INVALID_MEMORY_RANGE;
+ return ResultInvalidMemoryRange;
}
return page_table.UnmapProcessCodeMemory(dst_address, src_address, size);
@@ -1515,8 +1521,13 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
return ResultInvalidPriority;
}
- ASSERT(process.GetResourceLimit()->Reserve(
- LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000));
+ KScopedResourceReservation thread_reservation(
+ kernel.CurrentProcess(), LimitableResource::Threads, 1,
+ system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
+ if (!thread_reservation.Succeeded()) {
+ LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
+ return ResultResourceLimitedExceeded;
+ }
std::shared_ptr<KThread> thread;
{
@@ -1536,6 +1547,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
// Set the thread name for debugging purposes.
thread->SetName(
fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle));
+ thread_reservation.Commit();
return RESULT_SUCCESS;
}
@@ -1625,7 +1637,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address,
cv_key, tag, timeout_ns);
// Validate input.
- if (Memory::IsKernelAddress(address)) {
+ if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
@@ -1707,7 +1719,7 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit
address, arb_type, value, timeout_ns);
// Validate input.
- if (Memory::IsKernelAddress(address)) {
+ if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
@@ -1752,7 +1764,7 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
address, signal_type, value, count);
// Validate input.
- if (Memory::IsKernelAddress(address)) {
+ if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
@@ -1844,7 +1856,7 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) {
LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle);
- return Svc::ResultInvalidHandle;
+ return ResultInvalidHandle;
}
static ResultCode ResetSignal32(Core::System& system, Handle handle) {
@@ -1860,30 +1872,37 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
if (!Common::Is4KBAligned(addr)) {
LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(size) || size == 0) {
LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size);
- return ERR_INVALID_ADDRESS;
+ return ResultInvalidAddress;
}
if (!IsValidAddressRange(addr, size)) {
LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})",
addr, size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
- const auto perms{static_cast<Memory::MemoryPermission>(permissions)};
- if (perms > Memory::MemoryPermission::ReadAndWrite ||
- perms == Memory::MemoryPermission::Write) {
+ const auto perms{static_cast<MemoryPermission>(permissions)};
+ if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) {
LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})",
permissions);
- return ERR_INVALID_MEMORY_PERMISSIONS;
+ return ResultInvalidMemoryPermissions;
}
auto& kernel = system.Kernel();
- auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms);
+ // Reserve a new transfer memory from the process resource limit.
+ KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
+ LimitableResource::TransferMemory);
+ if (!trmem_reservation.Succeeded()) {
+ LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory");
+ return ResultResourceLimitedExceeded;
+ }
+ auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size,
+ static_cast<KMemoryPermission>(perms));
if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) {
return reserve_result;
@@ -1894,6 +1913,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
if (result.Failed()) {
return result.Code();
}
+ trmem_reservation.Commit();
*handle = *result;
return RESULT_SUCCESS;
@@ -1989,7 +2009,6 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
return set_result;
}
-
return RESULT_SUCCESS;
}
@@ -2002,8 +2021,17 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle
static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
+ auto& kernel = system.Kernel();
// Get the current handle table.
- const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
+ const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
+
+ // Reserve a new event from the process resource limit.
+ KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
+ LimitableResource::Events);
+ if (!event_reservation.Succeeded()) {
+ LOG_ERROR(Kernel, "Could not reserve a new event");
+ return ResultResourceLimitedExceeded;
+ }
// Get the writable event.
auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
@@ -2012,6 +2040,9 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
return ResultInvalidHandle;
}
+ // Commit the successfuly reservation.
+ event_reservation.Commit();
+
return writable_event->Signal();
}
@@ -2043,7 +2074,7 @@ static ResultCode ClearEvent(Core::System& system, Handle event_handle) {
LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle);
- return Svc::ResultInvalidHandle;
+ return ResultInvalidHandle;
}
static ResultCode ClearEvent32(Core::System& system, Handle event_handle) {
@@ -2106,13 +2137,13 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
if (!process) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
process_handle);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
const auto info_type = static_cast<InfoType>(type);
if (info_type != InfoType::Status) {
LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type);
- return ERR_INVALID_ENUM_VALUE;
+ return ResultInvalidEnumValue;
}
*out = static_cast<u64>(process->GetStatus());
@@ -2174,7 +2205,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
const auto type = static_cast<LimitableResource>(resource_type);
if (!IsValidResourceType(type)) {
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
- return ERR_INVALID_ENUM_VALUE;
+ return ResultInvalidEnumValue;
}
auto* const current_process = system.Kernel().CurrentProcess();
@@ -2185,16 +2216,16 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
if (!resource_limit_object) {
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
resource_limit);
- return ERR_INVALID_HANDLE;
+ return ResultInvalidHandle;
}
const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value));
if (set_result.IsError()) {
- LOG_ERROR(
- Kernel_SVC,
- "Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
- resource_limit_object->GetLimitValue(type), resource_type,
- resource_limit_object->GetCurrentValue(type));
+ LOG_ERROR(Kernel_SVC,
+ "Attempted to lower resource limit ({}) for category '{}' below its current "
+ "value ({})",
+ resource_limit_object->GetLimitValue(type), resource_type,
+ resource_limit_object->GetCurrentValue(type));
return set_result;
}
@@ -2211,7 +2242,7 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
LOG_ERROR(Kernel_SVC,
"Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}",
out_process_ids_size);
- return ERR_OUT_OF_RANGE;
+ return ResultOutOfRange;
}
const auto& kernel = system.Kernel();
@@ -2221,7 +2252,7 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
out_process_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_process_ids, out_process_ids + total_copy_size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
auto& memory = system.Memory();
@@ -2250,7 +2281,7 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
if ((out_thread_ids_size & 0xF0000000) != 0) {
LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}",
out_thread_ids_size);
- return ERR_OUT_OF_RANGE;
+ return ResultOutOfRange;
}
const auto* const current_process = system.Kernel().CurrentProcess();
@@ -2260,7 +2291,7 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
!current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_thread_ids, out_thread_ids + total_copy_size);
- return ERR_INVALID_ADDRESS_STATE;
+ return ResultInvalidCurrentMemory;
}
auto& memory = system.Memory();
diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h
index 204cd989d..a26d9f2c9 100644
--- a/src/core/hle/kernel/svc_results.h
+++ b/src/core/hle/kernel/svc_results.h
@@ -1,4 +1,4 @@
-// Copyright 2020 yuzu emulator team
+// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -6,21 +6,36 @@
#include "core/hle/result.h"
-namespace Kernel::Svc {
+namespace Kernel {
+// Confirmed Switch kernel error codes
+
+constexpr ResultCode ResultMaxConnectionsReached{ErrorModule::Kernel, 7};
+constexpr ResultCode ResultInvalidCapabilityDescriptor{ErrorModule::Kernel, 14};
constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
+constexpr ResultCode ResultInvalidSize{ErrorModule::Kernel, 101};
constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103};
+constexpr ResultCode ResultOutOfMemory{ErrorModule::Kernel, 104};
+constexpr ResultCode ResultHandleTableFull{ErrorModule::Kernel, 105};
constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
+constexpr ResultCode ResultInvalidMemoryPermissions{ErrorModule::Kernel, 108};
+constexpr ResultCode ResultInvalidMemoryRange{ErrorModule::Kernel, 110};
constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
+constexpr ResultCode ResultInvalidPointer{ErrorModule::Kernel, 115};
constexpr ResultCode ResultInvalidCombination{ErrorModule::Kernel, 116};
constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
+constexpr ResultCode ResultOutOfRange{ErrorModule::Kernel, 119};
constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120};
+constexpr ResultCode ResultNotFound{ErrorModule::Kernel, 121};
constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};
+constexpr ResultCode ResultSessionClosedByRemote{ErrorModule::Kernel, 123};
constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};
+constexpr ResultCode ResultReservedValue{ErrorModule::Kernel, 126};
+constexpr ResultCode ResultResourceLimitedExceeded{ErrorModule::Kernel, 132};
-} // namespace Kernel::Svc
+} // namespace Kernel
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp
index 765f408c3..cad063e4d 100644
--- a/src/core/hle/kernel/transfer_memory.cpp
+++ b/src/core/hle/kernel/transfer_memory.cpp
@@ -2,8 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory/page_table.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/result.h"
@@ -17,12 +18,13 @@ TransferMemory::TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory)
TransferMemory::~TransferMemory() {
// Release memory region when transfer memory is destroyed
Reset();
+ owner_process->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1);
}
std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel,
Core::Memory::Memory& memory,
VAddr base_address, std::size_t size,
- Memory::MemoryPermission permissions) {
+ KMemoryPermission permissions) {
std::shared_ptr<TransferMemory> transfer_memory{
std::make_shared<TransferMemory>(kernel, memory)};
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h
index 777799d12..521951424 100644
--- a/src/core/hle/kernel/transfer_memory.h
+++ b/src/core/hle/kernel/transfer_memory.h
@@ -6,7 +6,7 @@
#include <memory>
-#include "core/hle/kernel/memory/memory_block.h"
+#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/physical_memory.h"
@@ -36,7 +36,7 @@ public:
static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Core::Memory::Memory& memory,
VAddr base_address, std::size_t size,
- Memory::MemoryPermission permissions);
+ KMemoryPermission permissions);
TransferMemory(const TransferMemory&) = delete;
TransferMemory& operator=(const TransferMemory&) = delete;
@@ -82,7 +82,7 @@ private:
std::size_t size{};
/// The memory permissions that are applied to this instance.
- Memory::MemoryPermission owner_permissions{};
+ KMemoryPermission owner_permissions{};
/// The process that this transfer memory instance was created under.
Process* owner_process{};