Compare commits

..

77 Commits

Author SHA1 Message Date
Morph
d7e7944350 Revert "CMakeLists: Update boost to 1.81.0"
This reverts commit 877e8991c7.
2023-03-25 15:21:10 -04:00
Morph
8b0dc68848 Revert "vcpkg: Update vcpkg to 2023.02.24"
This reverts commit 032e5b983c.
2023-03-25 15:19:58 -04:00
bunnei
09da9da6fb Merge pull request #9985 from liamwhite/funny-meme
vulkan: fix scheduler chunk reserve
2023-03-24 23:40:17 -07:00
Morph
6892a0942f Merge pull request #9988 from rschlaikjer/rs-gpu-page-table-copy-elision
Pass GPU page table by reference inside TextureCache::ForEachImageInRegionGPU
2023-03-25 01:59:08 -04:00
Ross Schlaikjer
f38ae8e953 Pass GPU page table by reference 2023-03-25 00:25:02 -04:00
liamwhite
cfb9672093 Merge pull request #9983 from Morph1984/boost
CMakeLists: Update boost to 1.81.0
2023-03-24 10:53:30 -04:00
liamwhite
462c430c8b Merge pull request #9981 from german77/nfp_connect
nfc: Initialize device when controller is connected
2023-03-24 10:53:05 -04:00
Liam
5a2dff87bf vulkan: fix scheduler chunk reserve 2023-03-24 09:09:01 -04:00
Morph
7a8a7545f2 Merge pull request #9975 from liamwhite/more-waiting
vulkan: fix more excessive waiting in scheduler
2023-03-24 00:19:43 -04:00
Morph
abe2ad7aac zstd: Use ZSTD_getFrameContentSize instead of ZSTD_getDecompressedSize 2023-03-23 22:16:20 -04:00
Morph
877e8991c7 CMakeLists: Update boost to 1.81.0 2023-03-23 20:53:39 -04:00
Morph
032e5b983c vcpkg: Update vcpkg to 2023.02.24 2023-03-23 20:53:39 -04:00
liamwhite
ac3927074b Merge pull request #9971 from Morph1984/q
bounded_threadsafe_queue: Use simplified impl of bounded queue
2023-03-23 10:00:31 -04:00
liamwhite
c41a4baf06 Merge pull request #9964 from liamwhite/typed-address
kernel: use KTypedAddress for addresses
2023-03-23 10:00:19 -04:00
Morph
6adaa0d5e2 Merge pull request #9962 from Kelebek1/disable_srgb
[video_core] Disable SRGB border color conversion in samplers
2023-03-23 03:07:00 -04:00
Liam
fb49ec19c1 kernel: use KTypedAddress for addresses 2023-03-22 09:35:16 -04:00
Morph
197d756560 bounded_threadsafe_queue: Refactor Pop
Introduces PopModes to bring waiting logic into Pop, similar to Push.
2023-03-21 22:33:58 -04:00
Morph
8c56481249 bounded_threadsafe_queue: Add producer cv to avoid busy waiting 2023-03-21 22:33:57 -04:00
Narr the Reg
6ff4bf9b1c nfc: Initialize device when controller is connected 2023-03-21 20:09:36 -06:00
bunnei
dba86ee007 Merge pull request #9965 from german77/thankYouEpicBoy
config: Fix controller config from resetting
2023-03-21 17:52:25 -07:00
Morph
407dc917f1 bounded_threadsafe_queue: Deduplicate and add PushModes
Adds the PushModes Try and Wait to allow producers to specify how they want to push their data to the queue if the queue is full.
If the queue is full:
- Try will fail to push to the queue, returning false. Try only returns true if it successfully pushes to the queue. This may result in items not being pushed into the queue.
- Wait will wait until a slot is available to push to the queue, resulting in potential for deadlock if a consumer is not running.
2023-03-21 19:20:21 -04:00
Morph
15d573194c bounded_threadsafe_queue: Add TryPush 2023-03-21 19:17:38 -04:00
Morph
f28ca5361f logging: Make use of bounded queue 2023-03-21 19:17:38 -04:00
Morph
306840a580 bounded_threadsafe_queue: Use simplified impl of bounded queue
Provides a simplified SPSC, MPSC, and MPMC bounded queue implementation using mutexes.
2023-03-21 19:17:32 -04:00
bunnei
3d4c113037 Merge pull request #9970 from bunnei/string-util-view
common: string_util: Use std::string_view for UTF16ToUTF8/UTF8ToUTF16W.
2023-03-19 11:10:16 -07:00
bunnei
230d118252 Merge pull request #9972 from liamwhite/ipc-trace
kernel: fix LOG_TRACE in ipc
2023-03-19 11:00:42 -07:00
Liam
b9b1318bea vulkan: fix more excessive waiting in scheduler 2023-03-19 13:40:33 -04:00
Liam
43d909949e kernel: fix LOG_TRACE in ipc 2023-03-19 10:02:20 -04:00
bunnei
00d401d639 common: string_util: Use std::string_view for UTF16ToUTF8/UTF8ToUTF16W. 2023-03-18 22:42:25 -07:00
liamwhite
0e7e98e24e Merge pull request #9966 from bunnei/bounded-polyfill
common: bounded_threadsafe_queue: Use polyfill_thread.
2023-03-18 12:39:52 -04:00
bunnei
0eb3fa05e5 common: bounded_threadsafe_queue: Use polyfill_thread. 2023-03-17 23:42:17 -07:00
bunnei
889454f9bf Merge pull request #9778 from behunin/my-box-chevy
gpu_thread: Use bounded queue
2023-03-17 22:14:29 -07:00
bunnei
8bcaa8c2e4 Merge pull request #9953 from german77/amiibo_crc
service: nfp: Actually write correct crc
2023-03-17 22:13:57 -07:00
Narr the Reg
c95baf92ce config: Fix controller config from resetting 2023-03-17 22:08:16 -06:00
Kelebek1
a7651168dd Disable SRGB border color conversion for now, to fix shadows in Xenoblade. 2023-03-17 04:46:38 +00:00
Narr the Reg
075a3d1172 service: nfp: Replace crc function with boost equivalent 2023-03-16 17:47:32 -06:00
liamwhite
6d76a54d37 Merge pull request #9955 from liamwhite/color-blend-equation
vulkan: disable extendedDynamicState3ColorBlendEquation on radv
2023-03-15 20:19:45 -04:00
liamwhite
a04061e6ae Merge pull request #9931 from liamwhite/sched
vk_scheduler: split work queue waits and execution waits
2023-03-15 20:19:35 -04:00
Narr the Reg
7187732454 service: nfp: Close app area and recreate crc 2023-03-15 17:01:06 -06:00
Narr the Reg
5031f5b8b0 service: nfp: Convert mii colors to v3 2023-03-15 17:01:05 -06:00
Liam
da83afdeaf vulkan: disable extendedDynamicState3ColorBlendEquation on radv 2023-03-15 15:55:07 -04:00
Narr the Reg
026fe2e4f4 service: nfp: Actually write correct crc 2023-03-14 23:42:41 -06:00
liamwhite
0c7149d222 Merge pull request #9933 from vonchenplus/texture_format
video_core: Update texture format
2023-03-14 11:35:37 -04:00
bunnei
05f26e1337 Merge pull request #9951 from Morph1984/save
configure_audio: Fix output mode setting not saving
2023-03-13 18:49:14 -07:00
Morph
4c678cfbc8 configure_audio: Fix output mode setting not saving 2023-03-13 17:41:30 -04:00
liamwhite
8870fae674 Merge pull request #9939 from german77/vibration
input_common: sdl: Only send last vibration command
2023-03-13 13:45:40 -04:00
liamwhite
8348c41eab Merge pull request #9941 from german77/settings
yuzu: Move audio settings to audio section
2023-03-13 13:45:29 -04:00
liamwhite
638044820d Merge pull request #9943 from vonchenplus/gentleman
video_core: Fix inline_index and draw_texture error
2023-03-13 13:45:17 -04:00
liamwhite
1f952f6ac9 Merge pull request #9936 from liamwhite/m_this
kernel: use consistent style
2023-03-13 09:16:16 -04:00
german77
96b8a3ecac input_common: sdl: Only send last vibration command 2023-03-12 21:30:02 -06:00
Liam
c352381ce9 kernel: additional style fixes to KThread, KProcess 2023-03-12 22:10:27 -04:00
Liam
9775a73d1a kernel: fix clang build 2023-03-12 22:10:27 -04:00
Liam
088c434d65 kernel: remove unnecessary finalize calls 2023-03-12 22:10:27 -04:00
Liam
9863db9db4 kernel: convert KProcess to new style 2023-03-12 22:09:27 -04:00
Liam
6bfb4c8f71 kernel: convert KThread to new style 2023-03-12 22:09:09 -04:00
Liam
ac6cbb7134 kernel: prefer std::addressof 2023-03-12 22:09:09 -04:00
Liam
641783df8f kernel: convert KResourceLimit 2023-03-12 22:09:09 -04:00
Liam
c0b9e93b77 kernel: remove kernel_ 2023-03-12 22:09:09 -04:00
Liam
9368e17a92 kernel: remove gratitutous attribute usage 2023-03-12 22:09:09 -04:00
Liam
91fd4e30f2 kernel/svc: convert to new style 2023-03-12 22:09:08 -04:00
Liam
57f1d8ef8d kernel: convert miscellaneous 2023-03-12 22:06:53 -04:00
Liam
d1b53c8d82 kernel: conver KScopedLock, KScopedResourceReservation, KSessionRequest, KSharedMemory, KSpinLock 2023-03-12 22:06:53 -04:00
Liam
7322c99e5f kernel: convert KAbstractSchedulerLock 2023-03-12 22:06:53 -04:00
Liam
467adc1acd kernel: convert KMemoryLayout, KMemoryRegion*, KPageTableSlabHeap, KPriorityQueue 2023-03-12 22:06:53 -04:00
Liam
0483dfae1a kernel: move KMemoryLayout for NX board 2023-03-12 22:06:53 -04:00
Liam
8d1f5bfbd2 kernel: remove KLinkedList 2023-03-12 22:06:53 -04:00
Liam
fdf90c6d75 kernel: convert KConditionVariable, KLightConditionVariable, KLightLock 2023-03-12 22:06:53 -04:00
Liam
097c25b164 kernel: convert KPort, KSession 2023-03-12 22:06:53 -04:00
Liam
d24ab14126 kernel: convert GlobalSchedulerContext, KAddressArbiter, KScopedSchedulerLockAndSleep, KThreadQueue to new style 2023-03-12 22:06:53 -04:00
liamwhite
54c359d1e3 Merge pull request #9942 from liamwhite/speling
general: use codespell to identify spelling mistakes
2023-03-12 21:59:46 -04:00
Liam
3f261f22c9 vk_scheduler: split work queue waits and execution waits 2023-03-12 17:19:44 -04:00
FengChen
44f10c8dee video_core: Fix ogl status error when draw_texture 2023-03-12 13:33:31 +08:00
FengChen
4e42ba54e5 video_core: Invalid index_buffer flag when inline_index draw 2023-03-12 13:21:26 +08:00
german77
e090a1c6bd yuzu: Move audio settings to audio section 2023-03-11 20:04:36 -06:00
german77
e8af3f29d2 yuzu: Remove console id setting 2023-03-11 19:33:31 -06:00
Feng Chen
c8ad039612 video_core: Update texture format 2023-03-10 21:48:50 +08:00
Behunin
44518b225c gpu_thread: Use bounded queue 2023-03-03 18:20:56 -07:00
208 changed files with 4384 additions and 4229 deletions

View File

@@ -210,7 +210,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
# =======================================================================
# Enforce the search mode of non-required packages for better and shorter failure messages
find_package(Boost 1.73.0 REQUIRED context)
find_package(Boost 1.79.0 REQUIRED context)
find_package(enet 1.3 MODULE)
find_package(fmt 9 REQUIRED)
find_package(inih 52 MODULE COMPONENTS INIReader)

View File

@@ -132,6 +132,7 @@ add_library(common STATIC
time_zone.h
tiny_mt.h
tree.h
typed_address.h
uint128.h
unique_function.h
uuid.cpp

View File

@@ -1,158 +1,249 @@
// SPDX-FileCopyrightText: Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <bit>
#include <condition_variable>
#include <memory>
#include <cstddef>
#include <mutex>
#include <new>
#include <stop_token>
#include <type_traits>
#include <utility>
#include "common/polyfill_thread.h"
namespace Common {
#if defined(__cpp_lib_hardware_interference_size)
constexpr size_t hardware_interference_size = std::hardware_destructive_interference_size;
#else
constexpr size_t hardware_interference_size = 64;
#endif
namespace detail {
constexpr size_t DefaultCapacity = 0x1000;
} // namespace detail
template <typename T, size_t Capacity = detail::DefaultCapacity>
class SPSCQueue {
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
template <typename T, size_t capacity = 0x400>
class MPSCQueue {
public:
explicit MPSCQueue() : allocator{std::allocator<Slot<T>>()} {
// Allocate one extra slot to prevent false sharing on the last slot
slots = allocator.allocate(capacity + 1);
// Allocators are not required to honor alignment for over-aligned types
// (see http://eel.is/c++draft/allocator.requirements#10) so we verify
// alignment here
if (reinterpret_cast<uintptr_t>(slots) % alignof(Slot<T>) != 0) {
allocator.deallocate(slots, capacity + 1);
throw std::bad_alloc();
}
for (size_t i = 0; i < capacity; ++i) {
std::construct_at(&slots[i]);
}
static_assert(std::has_single_bit(capacity), "capacity must be an integer power of 2");
static_assert(alignof(Slot<T>) == hardware_interference_size,
"Slot must be aligned to cache line boundary to prevent false sharing");
static_assert(sizeof(Slot<T>) % hardware_interference_size == 0,
"Slot size must be a multiple of cache line size to prevent "
"false sharing between adjacent slots");
static_assert(sizeof(MPSCQueue) % hardware_interference_size == 0,
"Queue size must be a multiple of cache line size to "
"prevent false sharing between adjacent queues");
template <typename... Args>
bool TryEmplace(Args&&... args) {
return Emplace<PushMode::Try>(std::forward<Args>(args)...);
}
~MPSCQueue() noexcept {
for (size_t i = 0; i < capacity; ++i) {
std::destroy_at(&slots[i]);
}
allocator.deallocate(slots, capacity + 1);
template <typename... Args>
void EmplaceWait(Args&&... args) {
Emplace<PushMode::Wait>(std::forward<Args>(args)...);
}
// The queue must be both non-copyable and non-movable
MPSCQueue(const MPSCQueue&) = delete;
MPSCQueue& operator=(const MPSCQueue&) = delete;
MPSCQueue(MPSCQueue&&) = delete;
MPSCQueue& operator=(MPSCQueue&&) = delete;
void Push(const T& v) noexcept {
static_assert(std::is_nothrow_copy_constructible_v<T>,
"T must be nothrow copy constructible");
emplace(v);
bool TryPop(T& t) {
return Pop<PopMode::Try>(t);
}
template <typename P, typename = std::enable_if_t<std::is_nothrow_constructible_v<T, P&&>>>
void Push(P&& v) noexcept {
emplace(std::forward<P>(v));
void PopWait(T& t) {
Pop<PopMode::Wait>(t);
}
void Pop(T& v, std::stop_token stop) noexcept {
auto const tail = tail_.fetch_add(1);
auto& slot = slots[idx(tail)];
if (!slot.turn.test()) {
std::unique_lock lock{cv_mutex};
cv.wait(lock, stop, [&slot] { return slot.turn.test(); });
}
v = slot.move();
slot.destroy();
slot.turn.clear();
slot.turn.notify_one();
void PopWait(T& t, std::stop_token stop_token) {
Pop<PopMode::WaitWithStopToken>(t, stop_token);
}
T PopWait() {
T t;
Pop<PopMode::Wait>(t);
return t;
}
T PopWait(std::stop_token stop_token) {
T t;
Pop<PopMode::WaitWithStopToken>(t, stop_token);
return t;
}
private:
template <typename U = T>
struct Slot {
~Slot() noexcept {
if (turn.test()) {
destroy();
}
}
template <typename... Args>
void construct(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible_v<U, Args&&...>,
"T must be nothrow constructible with Args&&...");
std::construct_at(reinterpret_cast<U*>(&storage), std::forward<Args>(args)...);
}
void destroy() noexcept {
static_assert(std::is_nothrow_destructible_v<U>, "T must be nothrow destructible");
std::destroy_at(reinterpret_cast<U*>(&storage));
}
U&& move() noexcept {
return reinterpret_cast<U&&>(storage);
}
// Align to avoid false sharing between adjacent slots
alignas(hardware_interference_size) std::atomic_flag turn{};
struct aligned_store {
struct type {
alignas(U) unsigned char data[sizeof(U)];
};
};
typename aligned_store::type storage;
enum class PushMode {
Try,
Wait,
Count,
};
enum class PopMode {
Try,
Wait,
WaitWithStopToken,
Count,
};
template <PushMode Mode, typename... Args>
bool Emplace(Args&&... args) {
const size_t write_index = m_write_index.load(std::memory_order::relaxed);
if constexpr (Mode == PushMode::Try) {
// Check if we have free slots to write to.
if ((write_index - m_read_index.load(std::memory_order::acquire)) == Capacity) {
return false;
}
} else if constexpr (Mode == PushMode::Wait) {
// Wait until we have free slots to write to.
std::unique_lock lock{producer_cv_mutex};
producer_cv.wait(lock, [this, write_index] {
return (write_index - m_read_index.load(std::memory_order::acquire)) < Capacity;
});
} else {
static_assert(Mode < PushMode::Count, "Invalid PushMode.");
}
// Determine the position to write to.
const size_t pos = write_index % Capacity;
// Emplace into the queue.
std::construct_at(std::addressof(m_data[pos]), std::forward<Args>(args)...);
// Increment the write index.
++m_write_index;
// Notify the consumer that we have pushed into the queue.
std::scoped_lock lock{consumer_cv_mutex};
consumer_cv.notify_one();
return true;
}
template <PopMode Mode>
bool Pop(T& t, [[maybe_unused]] std::stop_token stop_token = {}) {
const size_t read_index = m_read_index.load(std::memory_order::relaxed);
if constexpr (Mode == PopMode::Try) {
// Check if the queue is empty.
if (read_index == m_write_index.load(std::memory_order::acquire)) {
return false;
}
} else if constexpr (Mode == PopMode::Wait) {
// Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex};
consumer_cv.wait(lock, [this, read_index] {
return read_index != m_write_index.load(std::memory_order::acquire);
});
} else if constexpr (Mode == PopMode::WaitWithStopToken) {
// Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex};
Common::CondvarWait(consumer_cv, lock, stop_token, [this, read_index] {
return read_index != m_write_index.load(std::memory_order::acquire);
});
if (stop_token.stop_requested()) {
return false;
}
} else {
static_assert(Mode < PopMode::Count, "Invalid PopMode.");
}
// Determine the position to read from.
const size_t pos = read_index % Capacity;
// Pop the data off the queue, moving it.
t = std::move(m_data[pos]);
// Increment the read index.
++m_read_index;
// Notify the producer that we have popped off the queue.
std::scoped_lock lock{producer_cv_mutex};
producer_cv.notify_one();
return true;
}
alignas(128) std::atomic_size_t m_read_index{0};
alignas(128) std::atomic_size_t m_write_index{0};
std::array<T, Capacity> m_data;
std::condition_variable_any producer_cv;
std::mutex producer_cv_mutex;
std::condition_variable_any consumer_cv;
std::mutex consumer_cv_mutex;
};
template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPSCQueue {
public:
template <typename... Args>
void emplace(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible_v<T, Args&&...>,
"T must be nothrow constructible with Args&&...");
auto const head = head_.fetch_add(1);
auto& slot = slots[idx(head)];
slot.turn.wait(true);
slot.construct(std::forward<Args>(args)...);
slot.turn.test_and_set();
cv.notify_one();
bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...);
}
constexpr size_t idx(size_t i) const noexcept {
return i & mask;
template <typename... Args>
void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...);
}
static constexpr size_t mask = capacity - 1;
bool TryPop(T& t) {
return spsc_queue.TryPop(t);
}
// Align to avoid false sharing between head_ and tail_
alignas(hardware_interference_size) std::atomic<size_t> head_{0};
alignas(hardware_interference_size) std::atomic<size_t> tail_{0};
void PopWait(T& t) {
spsc_queue.PopWait(t);
}
std::mutex cv_mutex;
std::condition_variable_any cv;
void PopWait(T& t, std::stop_token stop_token) {
spsc_queue.PopWait(t, stop_token);
}
Slot<T>* slots;
[[no_unique_address]] std::allocator<Slot<T>> allocator;
T PopWait() {
return spsc_queue.PopWait();
}
static_assert(std::is_nothrow_copy_assignable_v<T> || std::is_nothrow_move_assignable_v<T>,
"T must be nothrow copy or move assignable");
T PopWait(std::stop_token stop_token) {
return spsc_queue.PopWait(stop_token);
}
static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible");
private:
SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex;
};
template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPMCQueue {
public:
template <typename... Args>
bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...);
}
template <typename... Args>
void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...);
}
bool TryPop(T& t) {
std::scoped_lock lock{read_mutex};
return spsc_queue.TryPop(t);
}
void PopWait(T& t) {
std::scoped_lock lock{read_mutex};
spsc_queue.PopWait(t);
}
void PopWait(T& t, std::stop_token stop_token) {
std::scoped_lock lock{read_mutex};
spsc_queue.PopWait(t, stop_token);
}
T PopWait() {
std::scoped_lock lock{read_mutex};
return spsc_queue.PopWait();
}
T PopWait(std::stop_token stop_token) {
std::scoped_lock lock{read_mutex};
return spsc_queue.PopWait(stop_token);
}
private:
SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex;
std::mutex read_mutex;
};
} // namespace Common

View File

@@ -28,7 +28,7 @@
#ifdef _WIN32
#include "common/string_util.h"
#endif
#include "common/threadsafe_queue.h"
#include "common/bounded_threadsafe_queue.h"
namespace Common::Log {
@@ -204,11 +204,11 @@ public:
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, std::string&& message) {
if (!filter.CheckMessage(log_class, log_level))
if (!filter.CheckMessage(log_class, log_level)) {
return;
const Entry& entry =
CreateEntry(log_class, log_level, filename, line_num, function, std::move(message));
message_queue.Push(entry);
}
message_queue.EmplaceWait(
CreateEntry(log_class, log_level, filename, line_num, function, std::move(message)));
}
private:
@@ -225,7 +225,7 @@ private:
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
};
while (!stop_token.stop_requested()) {
entry = message_queue.PopWait(stop_token);
message_queue.PopWait(entry, stop_token);
if (entry.filename != nullptr) {
write_logs();
}
@@ -233,7 +233,7 @@ private:
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
// case where a system is repeatedly spamming logs even on close.
int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
while (max_logs_to_write-- && message_queue.Pop(entry)) {
while (max_logs_to_write-- && message_queue.TryPop(entry)) {
write_logs();
}
});
@@ -273,7 +273,7 @@ private:
ColorConsoleBackend color_console_backend{};
FileBackend file_backend;
MPSCQueue<Entry, true> message_queue{};
MPSCQueue<Entry> message_queue{};
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
std::jthread backend_thread;
};

View File

@@ -125,18 +125,18 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
return result;
}
std::string UTF16ToUTF8(const std::u16string& input) {
std::string UTF16ToUTF8(std::u16string_view input) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.to_bytes(input);
return convert.to_bytes(input.data(), input.data() + input.size());
}
std::u16string UTF8ToUTF16(const std::string& input) {
std::u16string UTF8ToUTF16(std::string_view input) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.from_bytes(input);
return convert.from_bytes(input.data(), input.data() + input.size());
}
#ifdef _WIN32
static std::wstring CPToUTF16(u32 code_page, const std::string& input) {
static std::wstring CPToUTF16(u32 code_page, std::string_view input) {
const auto size =
MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
@@ -154,7 +154,7 @@ static std::wstring CPToUTF16(u32 code_page, const std::string& input) {
return output;
}
std::string UTF16ToUTF8(const std::wstring& input) {
std::string UTF16ToUTF8(std::wstring_view input) {
const auto size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
nullptr, 0, nullptr, nullptr);
if (size == 0) {
@@ -172,7 +172,7 @@ std::string UTF16ToUTF8(const std::wstring& input) {
return output;
}
std::wstring UTF8ToUTF16W(const std::string& input) {
std::wstring UTF8ToUTF16W(std::string_view input) {
return CPToUTF16(CP_UTF8, input);
}

View File

@@ -36,12 +36,12 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
const std::string& dest);
[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input);
[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input);
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
#ifdef _WIN32
[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);
[[nodiscard]] std::wstring UTF8ToUTF16W(const std::string& str);
[[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input);
[[nodiscard]] std::wstring UTF8ToUTF16W(std::string_view str);
#endif

320
src/common/typed_address.h Normal file
View File

@@ -0,0 +1,320 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <compare>
#include <type_traits>
#include <fmt/format.h>
#include "common/common_types.h"
namespace Common {
template <bool Virtual, typename T>
class TypedAddress {
public:
// Constructors.
constexpr inline TypedAddress() : m_address(0) {}
constexpr inline TypedAddress(uint64_t a) : m_address(a) {}
template <typename U>
constexpr inline explicit TypedAddress(const U* ptr)
: m_address(reinterpret_cast<uint64_t>(ptr)) {}
// Copy constructor.
constexpr inline TypedAddress(const TypedAddress& rhs) = default;
// Assignment operator.
constexpr inline TypedAddress& operator=(const TypedAddress& rhs) = default;
// Arithmetic operators.
template <typename I>
constexpr inline TypedAddress operator+(I rhs) const {
static_assert(std::is_integral_v<I>);
return m_address + rhs;
}
constexpr inline TypedAddress operator+(TypedAddress rhs) const {
return m_address + rhs.m_address;
}
constexpr inline TypedAddress operator++() {
return ++m_address;
}
constexpr inline TypedAddress operator++(int) {
return m_address++;
}
template <typename I>
constexpr inline TypedAddress operator-(I rhs) const {
static_assert(std::is_integral_v<I>);
return m_address - rhs;
}
constexpr inline ptrdiff_t operator-(TypedAddress rhs) const {
return m_address - rhs.m_address;
}
constexpr inline TypedAddress operator--() {
return --m_address;
}
constexpr inline TypedAddress operator--(int) {
return m_address--;
}
template <typename I>
constexpr inline TypedAddress operator+=(I rhs) {
static_assert(std::is_integral_v<I>);
m_address += rhs;
return *this;
}
template <typename I>
constexpr inline TypedAddress operator-=(I rhs) {
static_assert(std::is_integral_v<I>);
m_address -= rhs;
return *this;
}
// Logical operators.
constexpr inline uint64_t operator&(uint64_t mask) const {
return m_address & mask;
}
constexpr inline uint64_t operator|(uint64_t mask) const {
return m_address | mask;
}
template <typename I>
constexpr inline TypedAddress operator|=(I rhs) {
static_assert(std::is_integral_v<I>);
m_address |= rhs;
return *this;
}
constexpr inline uint64_t operator<<(int shift) const {
return m_address << shift;
}
constexpr inline uint64_t operator>>(int shift) const {
return m_address >> shift;
}
template <typename U>
constexpr inline size_t operator/(U size) const {
return m_address / size;
}
constexpr explicit operator bool() const {
return m_address != 0;
}
// constexpr inline uint64_t operator%(U align) const { return m_address % align; }
// Comparison operators.
constexpr bool operator==(const TypedAddress&) const = default;
constexpr bool operator!=(const TypedAddress&) const = default;
constexpr auto operator<=>(const TypedAddress&) const = default;
// For convenience, also define comparison operators versus uint64_t.
constexpr inline bool operator==(uint64_t rhs) const {
return m_address == rhs;
}
constexpr inline bool operator!=(uint64_t rhs) const {
return m_address != rhs;
}
// Allow getting the address explicitly, for use in accessors.
constexpr inline uint64_t GetValue() const {
return m_address;
}
private:
uint64_t m_address{};
};
struct PhysicalAddressTag {};
struct VirtualAddressTag {};
struct ProcessAddressTag {};
using PhysicalAddress = TypedAddress<false, PhysicalAddressTag>;
using VirtualAddress = TypedAddress<true, VirtualAddressTag>;
using ProcessAddress = TypedAddress<true, ProcessAddressTag>;
// Define accessors.
template <typename T>
concept IsTypedAddress = std::same_as<T, PhysicalAddress> || std::same_as<T, VirtualAddress> ||
std::same_as<T, ProcessAddress>;
template <typename T>
constexpr inline T Null = [] {
if constexpr (std::is_same<T, uint64_t>::value) {
return 0;
} else {
static_assert(std::is_same<T, PhysicalAddress>::value ||
std::is_same<T, VirtualAddress>::value ||
std::is_same<T, ProcessAddress>::value);
return T(0);
}
}();
// Basic type validations.
static_assert(sizeof(PhysicalAddress) == sizeof(uint64_t));
static_assert(sizeof(VirtualAddress) == sizeof(uint64_t));
static_assert(sizeof(ProcessAddress) == sizeof(uint64_t));
static_assert(std::is_trivially_copyable_v<PhysicalAddress>);
static_assert(std::is_trivially_copyable_v<VirtualAddress>);
static_assert(std::is_trivially_copyable_v<ProcessAddress>);
static_assert(std::is_trivially_copy_constructible_v<PhysicalAddress>);
static_assert(std::is_trivially_copy_constructible_v<VirtualAddress>);
static_assert(std::is_trivially_copy_constructible_v<ProcessAddress>);
static_assert(std::is_trivially_move_constructible_v<PhysicalAddress>);
static_assert(std::is_trivially_move_constructible_v<VirtualAddress>);
static_assert(std::is_trivially_move_constructible_v<ProcessAddress>);
static_assert(std::is_trivially_copy_assignable_v<PhysicalAddress>);
static_assert(std::is_trivially_copy_assignable_v<VirtualAddress>);
static_assert(std::is_trivially_copy_assignable_v<ProcessAddress>);
static_assert(std::is_trivially_move_assignable_v<PhysicalAddress>);
static_assert(std::is_trivially_move_assignable_v<VirtualAddress>);
static_assert(std::is_trivially_move_assignable_v<ProcessAddress>);
static_assert(std::is_trivially_destructible_v<PhysicalAddress>);
static_assert(std::is_trivially_destructible_v<VirtualAddress>);
static_assert(std::is_trivially_destructible_v<ProcessAddress>);
static_assert(Null<uint64_t> == 0);
static_assert(Null<PhysicalAddress> == Null<uint64_t>);
static_assert(Null<VirtualAddress> == Null<uint64_t>);
static_assert(Null<ProcessAddress> == Null<uint64_t>);
// Constructor/assignment validations.
static_assert([] {
const PhysicalAddress a(5);
PhysicalAddress b(a);
return b;
}() == PhysicalAddress(5));
static_assert([] {
const PhysicalAddress a(5);
PhysicalAddress b(10);
b = a;
return b;
}() == PhysicalAddress(5));
// Arithmetic validations.
static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15));
static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5));
static_assert([] {
PhysicalAddress v(10);
v += 5;
return v;
}() == PhysicalAddress(15));
static_assert([] {
PhysicalAddress v(10);
v -= 5;
return v;
}() == PhysicalAddress(5));
static_assert(PhysicalAddress(10)++ == PhysicalAddress(10));
static_assert(++PhysicalAddress(10) == PhysicalAddress(11));
static_assert(PhysicalAddress(10)-- == PhysicalAddress(10));
static_assert(--PhysicalAddress(10) == PhysicalAddress(9));
// Logical validations.
static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111);
static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101);
static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110);
static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010);
static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101);
static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010);
static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000);
static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101);
static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111);
static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111);
// Comparisons.
static_assert(PhysicalAddress(0) == PhysicalAddress(0));
static_assert(PhysicalAddress(0) != PhysicalAddress(1));
static_assert(PhysicalAddress(0) < PhysicalAddress(1));
static_assert(PhysicalAddress(0) <= PhysicalAddress(1));
static_assert(PhysicalAddress(1) > PhysicalAddress(0));
static_assert(PhysicalAddress(1) >= PhysicalAddress(0));
static_assert(!(PhysicalAddress(0) == PhysicalAddress(1)));
static_assert(!(PhysicalAddress(0) != PhysicalAddress(0)));
static_assert(!(PhysicalAddress(1) < PhysicalAddress(0)));
static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0)));
static_assert(!(PhysicalAddress(0) > PhysicalAddress(1)));
static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1)));
} // namespace Common
template <bool Virtual, typename T>
constexpr inline uint64_t GetInteger(Common::TypedAddress<Virtual, T> address) {
return address.GetValue();
}
template <>
struct fmt::formatter<Common::PhysicalAddress> {
constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Common::PhysicalAddress& addr, FormatContext& ctx) {
return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
}
};
template <>
struct fmt::formatter<Common::ProcessAddress> {
constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Common::ProcessAddress& addr, FormatContext& ctx) {
return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
}
};
template <>
struct fmt::formatter<Common::VirtualAddress> {
constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Common::VirtualAddress& addr, FormatContext& ctx) {
return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
}
};
namespace std {
template <>
struct hash<Common::PhysicalAddress> {
size_t operator()(const Common::PhysicalAddress& k) const noexcept {
return k.GetValue();
}
};
template <>
struct hash<Common::ProcessAddress> {
size_t operator()(const Common::ProcessAddress& k) const noexcept {
return k.GetValue();
}
};
template <>
struct hash<Common::VirtualAddress> {
size_t operator()(const Common::VirtualAddress& k) const noexcept {
return k.GetValue();
}
};
} // namespace std

View File

@@ -33,7 +33,7 @@ std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_siz
std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed) {
const std::size_t decompressed_size =
ZSTD_getDecompressedSize(compressed.data(), compressed.size());
ZSTD_getFrameContentSize(compressed.data(), compressed.size());
std::vector<u8> decompressed(decompressed_size);
const std::size_t uncompressed_result_size = ZSTD_decompress(

View File

@@ -158,6 +158,7 @@ add_library(core STATIC
hid/motion_input.h
hle/api_version.h
hle/ipc.h
hle/kernel/board/nintendo/nx/k_memory_layout.cpp
hle/kernel/board/nintendo/nx/k_memory_layout.h
hle/kernel/board/nintendo/nx/k_system_control.cpp
hle/kernel/board/nintendo/nx/k_system_control.h
@@ -211,12 +212,10 @@ add_library(core STATIC
hle/kernel/k_light_condition_variable.h
hle/kernel/k_light_lock.cpp
hle/kernel/k_light_lock.h
hle/kernel/k_linked_list.h
hle/kernel/k_memory_block.h
hle/kernel/k_memory_block_manager.cpp
hle/kernel/k_memory_block_manager.h
hle/kernel/k_memory_layout.cpp
hle/kernel/k_memory_layout.board.nintendo_nx.cpp
hle/kernel/k_memory_layout.h
hle/kernel/k_memory_manager.cpp
hle/kernel/k_memory_manager.h
@@ -279,6 +278,7 @@ add_library(core STATIC
hle/kernel/k_trace.h
hle/kernel/k_transfer_memory.cpp
hle/kernel/k_transfer_memory.h
hle/kernel/k_typed_address.h
hle/kernel/k_worker_task.h
hle/kernel/k_worker_task_manager.cpp
hle/kernel/k_worker_task_manager.h

View File

@@ -168,21 +168,21 @@ void ARM_Interface::LoadWatchpointArray(const WatchpointArray& wp) {
}
const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint(
VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const {
u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const {
if (!watchpoints) {
return nullptr;
}
const VAddr start_address{addr};
const VAddr end_address{addr + size};
const u64 start_address{addr};
const u64 end_address{addr + size};
for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) {
const auto& watch{(*watchpoints)[i]};
if (end_address <= watch.start_address) {
if (end_address <= GetInteger(watch.start_address)) {
continue;
}
if (start_address >= watch.end_address) {
if (start_address >= GetInteger(watch.end_address)) {
continue;
}
if ((access_type & watch.type) == Kernel::DebugWatchpointType::None) {

View File

@@ -78,7 +78,7 @@ public:
* @param addr Start address of the cache range to clear
* @param size Size of the cache range to clear, starting at addr
*/
virtual void InvalidateCacheRange(VAddr addr, std::size_t size) = 0;
virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0;
/**
* Notifies CPU emulation that the current page table has changed.
@@ -149,9 +149,9 @@ public:
*/
virtual void SetPSTATE(u32 pstate) = 0;
virtual VAddr GetTlsAddress() const = 0;
virtual u64 GetTlsAddress() const = 0;
virtual void SetTlsAddress(VAddr address) = 0;
virtual void SetTlsAddress(u64 address) = 0;
/**
* Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
@@ -214,7 +214,7 @@ protected:
static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out);
const Kernel::DebugWatchpoint* MatchingWatchpoint(
VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const;
u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const;
virtual Dynarmic::HaltReason RunJit() = 0;
virtual Dynarmic::HaltReason StepJit() = 0;

View File

@@ -155,7 +155,7 @@ public:
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
}
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
@@ -397,7 +397,7 @@ u64 ARM_Dynarmic_32::GetTlsAddress() const {
return cp15->uro;
}
void ARM_Dynarmic_32::SetTlsAddress(VAddr address) {
void ARM_Dynarmic_32::SetTlsAddress(u64 address) {
cp15->uro = static_cast<u32>(address);
}
@@ -439,7 +439,7 @@ void ARM_Dynarmic_32::ClearInstructionCache() {
jit.load()->ClearCache();
}
void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
void ARM_Dynarmic_32::InvalidateCacheRange(u64 addr, std::size_t size) {
jit.load()->InvalidateCacheRange(static_cast<u32>(addr), size);
}

View File

@@ -41,8 +41,8 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
u64 GetTlsAddress() const override;
void SetTlsAddress(u64 address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
@@ -60,7 +60,7 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void InvalidateCacheRange(u64 addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;

View File

@@ -117,7 +117,7 @@ public:
}
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
VAddr value) override {
u64 value) override {
switch (op) {
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
static constexpr u64 ICACHE_LINE_SIZE = 64;
@@ -199,7 +199,7 @@ public:
return parent.system.CoreTiming().GetClockTicks();
}
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
@@ -452,7 +452,7 @@ u64 ARM_Dynarmic_64::GetTlsAddress() const {
return cb->tpidrro_el0;
}
void ARM_Dynarmic_64::SetTlsAddress(VAddr address) {
void ARM_Dynarmic_64::SetTlsAddress(u64 address) {
cb->tpidrro_el0 = address;
}
@@ -500,7 +500,7 @@ void ARM_Dynarmic_64::ClearInstructionCache() {
jit.load()->ClearCache();
}
void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
void ARM_Dynarmic_64::InvalidateCacheRange(u64 addr, std::size_t size) {
jit.load()->InvalidateCacheRange(addr, size);
}

View File

@@ -38,8 +38,8 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
u64 GetTlsAddress() const override;
void SetTlsAddress(u64 address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
@@ -53,7 +53,7 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void InvalidateCacheRange(u64 addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;

View File

@@ -434,7 +434,7 @@ struct System::Impl {
}
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process.GetProgramID();
launch.title_id = process.GetProgramId();
FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
launch.version = pm.GetGameVersion().value_or(0);
@@ -564,7 +564,7 @@ void System::InvalidateCpuInstructionCaches() {
impl->kernel.InvalidateAllInstructionCaches();
}
void System::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
void System::InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size) {
impl->kernel.InvalidateCpuInstructionCacheRange(addr, size);
}
@@ -762,7 +762,7 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
}
u64 System::GetApplicationProcessProgramID() const {
return impl->kernel.ApplicationProcess()->GetProgramID();
return impl->kernel.ApplicationProcess()->GetProgramId();
}
Loader::ResultStatus System::GetGameName(std::string& out) const {
@@ -794,7 +794,7 @@ FileSys::VirtualFilesystem System::GetFilesystem() const {
}
void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 32>& build_id, VAddr main_region_begin,
const std::array<u8, 32>& build_id, u64 main_region_begin,
u64 main_region_size) {
impl->cheat_engine = std::make_unique<Memory::CheatEngine>(*this, list, build_id);
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);

View File

@@ -172,7 +172,7 @@ public:
*/
void InvalidateCpuInstructionCaches();
void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
void InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size);
/// Shutdown the main emulated process.
void ShutdownMainProcess();
@@ -353,7 +353,7 @@ public:
[[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
const std::array<u8, 0x20>& build_id, u64 main_region_begin,
u64 main_region_size);
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);

View File

@@ -118,14 +118,14 @@ void GDBStub::Watchpoint(Kernel::KThread* thread, const Kernel::DebugWatchpoint&
switch (watch.type) {
case Kernel::DebugWatchpointType::Read:
SendReply(fmt::format("{}rwatch:{:x};", status, watch.start_address));
SendReply(fmt::format("{}rwatch:{:x};", status, GetInteger(watch.start_address)));
break;
case Kernel::DebugWatchpointType::Write:
SendReply(fmt::format("{}watch:{:x};", status, watch.start_address));
SendReply(fmt::format("{}watch:{:x};", status, GetInteger(watch.start_address)));
break;
case Kernel::DebugWatchpointType::ReadOrWrite:
default:
SendReply(fmt::format("{}awatch:{:x};", status, watch.start_address));
SendReply(fmt::format("{}awatch:{:x};", status, GetInteger(watch.start_address)));
break;
}
}
@@ -421,7 +421,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
const Kernel::KThread* thread) {
// Read thread type from TLS
const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)};
const VAddr tls_thread_type{memory.Read32(thread->GetTlsAddress() + 0x1fc)};
const VAddr argument_thread_type{thread->GetArgument()};
if (argument_thread_type && tls_thread_type != argument_thread_type) {
@@ -452,7 +452,7 @@ static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory&
static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
const Kernel::KThread* thread) {
// Read thread type from TLS
const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)};
const VAddr tls_thread_type{memory.Read64(thread->GetTlsAddress() + 0x1f8)};
const VAddr argument_thread_type{thread->GetArgument()};
if (argument_thread_type && tls_thread_type != argument_thread_type) {
@@ -554,8 +554,9 @@ void GDBStub::HandleQuery(std::string_view command) {
if (main != modules.end()) {
SendReply(fmt::format("TextSeg={:x}", main->first));
} else {
SendReply(fmt::format("TextSeg={:x}",
system.ApplicationProcess()->PageTable().GetCodeRegionStart()));
SendReply(fmt::format(
"TextSeg={:x}",
GetInteger(system.ApplicationProcess()->PageTable().GetCodeRegionStart())));
}
} else if (command.starts_with("Xfer:libraries:read::")) {
Loader::AppLoader::Modules modules;
@@ -576,7 +577,7 @@ void GDBStub::HandleQuery(std::string_view command) {
const auto& threads = system.ApplicationProcess()->GetThreadList();
std::vector<std::string> thread_ids;
for (const auto& thread : threads) {
thread_ids.push_back(fmt::format("{:x}", thread->GetThreadID()));
thread_ids.push_back(fmt::format("{:x}", thread->GetThreadId()));
}
SendReply(fmt::format("m{}", fmt::join(thread_ids, ",")));
} else if (command.starts_with("sThreadInfo")) {
@@ -591,11 +592,11 @@ void GDBStub::HandleQuery(std::string_view command) {
for (const auto* thread : threads) {
auto thread_name{GetThreadName(system, thread)};
if (!thread_name) {
thread_name = fmt::format("Thread {:d}", thread->GetThreadID());
thread_name = fmt::format("Thread {:d}", thread->GetThreadId());
}
buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)",
thread->GetThreadID(), thread->GetActiveCore(),
thread->GetThreadId(), thread->GetActiveCore(),
EscapeXML(*thread_name), GetThreadState(thread));
}
@@ -756,18 +757,21 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
reply = fmt::format("Process: {:#x} ({})\n"
"Program Id: {:#018x}\n",
process->GetProcessID(), process->GetName(), process->GetProgramID());
reply +=
fmt::format("Layout:\n"
" Alias: {:#012x} - {:#012x}\n"
" Heap: {:#012x} - {:#012x}\n"
" Aslr: {:#012x} - {:#012x}\n"
" Stack: {:#012x} - {:#012x}\n"
"Modules:\n",
page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(),
page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(),
page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(),
page_table.GetStackRegionStart(), page_table.GetStackRegionEnd());
process->GetProcessId(), process->GetName(), process->GetProgramId());
reply += fmt::format("Layout:\n"
" Alias: {:#012x} - {:#012x}\n"
" Heap: {:#012x} - {:#012x}\n"
" Aslr: {:#012x} - {:#012x}\n"
" Stack: {:#012x} - {:#012x}\n"
"Modules:\n",
GetInteger(page_table.GetAliasRegionStart()),
GetInteger(page_table.GetAliasRegionEnd()),
GetInteger(page_table.GetHeapRegionStart()),
GetInteger(page_table.GetHeapRegionEnd()),
GetInteger(page_table.GetAliasCodeRegionStart()),
GetInteger(page_table.GetAliasCodeRegionEnd()),
GetInteger(page_table.GetStackRegionStart()),
GetInteger(page_table.GetStackRegionEnd()));
for (const auto& [vaddr, name] : modules) {
reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
@@ -819,7 +823,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) {
const auto& threads{system.ApplicationProcess()->GetThreadList()};
for (auto* thread : threads) {
if (thread->GetThreadID() == thread_id) {
if (thread->GetThreadId() == thread_id) {
return thread;
}
}

View File

@@ -259,7 +259,7 @@ void GDBStubA64::WriteRegisters(Kernel::KThread* thread, std::string_view regist
std::string GDBStubA64::ThreadStatus(const Kernel::KThread* thread, u8 signal) const {
return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER,
RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER),
LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID());
LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadId());
}
u32 GDBStubA64::BreakpointInstruction() const {
@@ -469,7 +469,7 @@ void GDBStubA32::WriteRegisters(Kernel::KThread* thread, std::string_view regist
std::string GDBStubA32::ThreadStatus(const Kernel::KThread* thread, u8 signal) const {
return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER,
RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER),
LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID());
LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadId());
}
u32 GDBStubA32::BreakpointInstruction() const {

View File

@@ -3,8 +3,8 @@
#pragma once
#include "common/common_types.h"
#include "common/host_memory.h"
#include "common/typed_address.h"
namespace Core {
@@ -25,20 +25,22 @@ public:
DeviceMemory(const DeviceMemory&) = delete;
template <typename T>
PAddr GetPhysicalAddr(const T* ptr) const {
Common::PhysicalAddress GetPhysicalAddr(const T* ptr) const {
return (reinterpret_cast<uintptr_t>(ptr) -
reinterpret_cast<uintptr_t>(buffer.BackingBasePointer())) +
DramMemoryMap::Base;
}
template <typename T>
T* GetPointer(PAddr addr) {
return reinterpret_cast<T*>(buffer.BackingBasePointer() + (addr - DramMemoryMap::Base));
T* GetPointer(Common::PhysicalAddress addr) {
return reinterpret_cast<T*>(buffer.BackingBasePointer() +
(GetInteger(addr) - DramMemoryMap::Base));
}
template <typename T>
const T* GetPointer(PAddr addr) const {
return reinterpret_cast<T*>(buffer.BackingBasePointer() + (addr - DramMemoryMap::Base));
const T* GetPointer(Common::PhysicalAddress addr) const {
return reinterpret_cast<T*>(buffer.BackingBasePointer() +
(GetInteger(addr) - DramMemoryMap::Base));
}
Common::HostMemory buffer;

View File

@@ -76,22 +76,24 @@ void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout) {
void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout) {
const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize();
const PAddr physical_memory_base_address =
const KPhysicalAddress physical_memory_base_address =
KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress);
// Insert blocks into the tree.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
physical_memory_base_address, intended_memory_size, KMemoryRegionType_Dram));
GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
physical_memory_base_address, ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly));
GetInteger(physical_memory_base_address), ReservedEarlyDramSize,
KMemoryRegionType_DramReservedEarly));
// Insert the KTrace block at the end of Dram, if KTrace is enabled.
static_assert(!IsKTraceEnabled || KTraceBufferSize > 0);
if constexpr (IsKTraceEnabled) {
const PAddr ktrace_buffer_phys_addr =
const KPhysicalAddress ktrace_buffer_phys_addr =
physical_memory_base_address + intended_memory_size - KTraceBufferSize;
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
ktrace_buffer_phys_addr, KTraceBufferSize, KMemoryRegionType_KernelTraceBuffer));
GetInteger(ktrace_buffer_phys_addr), KTraceBufferSize,
KMemoryRegionType_KernelTraceBuffer));
}
}

View File

@@ -3,10 +3,10 @@
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
constexpr inline PAddr MainMemoryAddress = 0x80000000;
constexpr inline KPhysicalAddress MainMemoryAddress = 0x80000000;
} // namespace Kernel

View File

@@ -61,7 +61,7 @@ size_t KSystemControl::Init::GetIntendedMemorySize() {
}
}
PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
KPhysicalAddress KSystemControl::Init::GetKernelPhysicalBaseAddress(KPhysicalAddress base_address) {
const size_t real_dram_size = KSystemControl::Init::GetRealMemorySize();
const size_t intended_dram_size = KSystemControl::Init::GetIntendedMemorySize();
if (intended_dram_size * 2 < real_dram_size) {

View File

@@ -3,7 +3,7 @@
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/k_typed_address.h"
namespace Kernel::Board::Nintendo::Nx {
@@ -18,7 +18,7 @@ public:
// Initialization.
static std::size_t GetRealMemorySize();
static std::size_t GetIntendedMemorySize();
static PAddr GetKernelPhysicalBaseAddress(u64 base_address);
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
static bool ShouldIncreaseThreadResourceLimit();
static std::size_t GetApplicationPoolSize();
static std::size_t GetAppletPoolSize();

View File

@@ -5,7 +5,7 @@
#include <cstddef>
#include "common/common_types.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/physical_memory.h"
namespace Kernel {
@@ -36,7 +36,7 @@ struct CodeSet final {
std::size_t offset = 0;
/// The address to map this segment to.
VAddr addr = 0;
KProcessAddress addr = 0;
/// The size of this segment in bytes.
u32 size = 0;
@@ -82,7 +82,7 @@ struct CodeSet final {
std::array<Segment, 3> segments;
/// The entry point address for this code set.
VAddr entrypoint = 0;
KProcessAddress entrypoint = 0;
};
} // namespace Kernel

View File

@@ -12,20 +12,19 @@
namespace Kernel {
GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel_)
: kernel{kernel_}, scheduler_lock{kernel_} {}
GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
: m_kernel{kernel}, m_scheduler_lock{kernel} {}
GlobalSchedulerContext::~GlobalSchedulerContext() = default;
void GlobalSchedulerContext::AddThread(KThread* thread) {
std::scoped_lock lock{global_list_guard};
thread_list.push_back(thread);
std::scoped_lock lock{m_global_list_guard};
m_thread_list.push_back(thread);
}
void GlobalSchedulerContext::RemoveThread(KThread* thread) {
std::scoped_lock lock{global_list_guard};
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
thread_list.end());
std::scoped_lock lock{m_global_list_guard};
std::erase(m_thread_list, thread);
}
void GlobalSchedulerContext::PreemptThreads() {
@@ -38,37 +37,37 @@ void GlobalSchedulerContext::PreemptThreads() {
63,
};
ASSERT(IsLocked());
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
const u32 priority = preemption_priorities[core_id];
KScheduler::RotateScheduledQueue(kernel, core_id, priority);
KScheduler::RotateScheduledQueue(m_kernel, core_id, priority);
}
}
bool GlobalSchedulerContext::IsLocked() const {
return scheduler_lock.IsLockedByCurrentThread();
return m_scheduler_lock.IsLockedByCurrentThread();
}
void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) {
ASSERT(IsLocked());
ASSERT(this->IsLocked());
woken_dummy_threads.insert(thread);
m_woken_dummy_threads.insert(thread);
}
void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) {
ASSERT(IsLocked());
ASSERT(this->IsLocked());
woken_dummy_threads.erase(thread);
m_woken_dummy_threads.erase(thread);
}
void GlobalSchedulerContext::WakeupWaitingDummyThreads() {
ASSERT(IsLocked());
ASSERT(this->IsLocked());
for (auto* thread : woken_dummy_threads) {
for (auto* thread : m_woken_dummy_threads) {
thread->DummyThreadEndWait();
}
woken_dummy_threads.clear();
m_woken_dummy_threads.clear();
}
} // namespace Kernel

View File

@@ -33,7 +33,7 @@ class GlobalSchedulerContext final {
public:
using LockType = KAbstractSchedulerLock<KScheduler>;
explicit GlobalSchedulerContext(KernelCore& kernel_);
explicit GlobalSchedulerContext(KernelCore& kernel);
~GlobalSchedulerContext();
/// Adds a new thread to the scheduler
@@ -43,8 +43,9 @@ public:
void RemoveThread(KThread* thread);
/// Returns a list of all threads managed by the scheduler
[[nodiscard]] const std::vector<KThread*>& GetThreadList() const {
return thread_list;
/// This is only safe to iterate while holding the scheduler lock
const std::vector<KThread*>& GetThreadList() const {
return m_thread_list;
}
/**
@@ -63,30 +64,26 @@ public:
void RegisterDummyThreadForWakeup(KThread* thread);
void WakeupWaitingDummyThreads();
[[nodiscard]] LockType& SchedulerLock() {
return scheduler_lock;
}
[[nodiscard]] const LockType& SchedulerLock() const {
return scheduler_lock;
LockType& SchedulerLock() {
return m_scheduler_lock;
}
private:
friend class KScopedSchedulerLock;
friend class KScopedSchedulerLockAndSleep;
KernelCore& kernel;
KernelCore& m_kernel;
std::atomic_bool scheduler_update_needed{};
KSchedulerPriorityQueue priority_queue;
LockType scheduler_lock;
std::atomic_bool m_scheduler_update_needed{};
KSchedulerPriorityQueue m_priority_queue;
LockType m_scheduler_lock;
/// Lists dummy threads pending wakeup on lock release
std::set<KThread*> woken_dummy_threads;
std::set<KThread*> m_woken_dummy_threads;
/// Lists all thread ids that aren't deleted/etc.
std::vector<KThread*> thread_list;
std::mutex global_list_guard;
std::vector<KThread*> m_thread_list;
std::mutex m_global_list_guard;
};
} // namespace Kernel

View File

@@ -4,7 +4,6 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/core.h"
#include "core/device_memory.h"
#include "core/hardware_properties.h"
@@ -30,6 +29,7 @@
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_local_page.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/k_typed_address.h"
namespace Kernel::Init {
@@ -104,17 +104,18 @@ static_assert(KernelPageBufferAdditionalSize ==
/// Helper function to translate from the slab virtual address to the reserved location in physical
/// memory.
static PAddr TranslateSlabAddrToPhysical(KMemoryLayout& memory_layout, VAddr slab_addr) {
slab_addr -= memory_layout.GetSlabRegionAddress();
return slab_addr + Core::DramMemoryMap::SlabHeapBase;
static KPhysicalAddress TranslateSlabAddrToPhysical(KMemoryLayout& memory_layout,
KVirtualAddress slab_addr) {
slab_addr -= GetInteger(memory_layout.GetSlabRegionAddress());
return GetInteger(slab_addr) + Core::DramMemoryMap::SlabHeapBase;
}
template <typename T>
VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address,
size_t num_objects) {
KVirtualAddress InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout,
KVirtualAddress address, size_t num_objects) {
const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*));
VAddr start = Common::AlignUp(address, alignof(T));
KVirtualAddress start = Common::AlignUp(GetInteger(address), alignof(T));
// This should use the virtual memory address passed in, but currently, we do not setup the
// kernel virtual memory layout. Instead, we simply map these at a region of physical memory
@@ -195,7 +196,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
auto& kernel = system.Kernel();
// Get the start of the slab region, since that's where we'll be working.
VAddr address = memory_layout.GetSlabRegionAddress();
KVirtualAddress address = memory_layout.GetSlabRegionAddress();
// Initialize slab type array to be in sorted order.
std::array<KSlabType, KSlabType_Count> slab_types;
@@ -228,7 +229,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
}
// Track the gaps, so that we can free them to the unused slab tree.
VAddr gap_start = address;
KVirtualAddress gap_start = address;
size_t gap_size = 0;
for (size_t i = 0; i < slab_gaps.size(); i++) {
@@ -280,7 +281,7 @@ void KPageBufferSlabHeap::Initialize(Core::System& system) {
// Allocate memory for the slab.
constexpr auto AllocateOption = KMemoryManager::EncodeOption(
KMemoryManager::Pool::System, KMemoryManager::Direction::FromFront);
const PAddr slab_address =
const KPhysicalAddress slab_address =
kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, AllocateOption);
ASSERT(slab_address != 0);

View File

@@ -14,7 +14,7 @@ using namespace Common::Literals;
constexpr std::size_t InitialProcessBinarySizeMax = 12_MiB;
static inline PAddr GetInitialProcessBinaryPhysicalAddress() {
static inline KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
return Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetKernelPhysicalBaseAddress(
MainMemoryAddress);
}

View File

@@ -8,24 +8,25 @@
#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/k_typed_address.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
#include "core/memory.h"
namespace Kernel {
KAddressArbiter::KAddressArbiter(Core::System& system_)
: system{system_}, kernel{system.Kernel()} {}
KAddressArbiter::KAddressArbiter(Core::System& system)
: m_system{system}, m_kernel{system.Kernel()} {}
KAddressArbiter::~KAddressArbiter() = default;
namespace {
bool ReadFromUser(Core::System& system, s32* out, VAddr address) {
*out = system.Memory().Read32(address);
bool ReadFromUser(Core::System& system, s32* out, KProcessAddress address) {
*out = system.Memory().Read32(GetInteger(address));
return true;
}
bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) {
bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) {
auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
@@ -35,7 +36,8 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
// TODO(bunnei): We should call CanAccessAtomic(..) here.
// Load the value from the address.
const s32 current_value = static_cast<s32>(monitor.ExclusiveRead32(current_core, address));
const s32 current_value =
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
// Compare it to the desired one.
if (current_value < value) {
@@ -43,7 +45,8 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
const s32 decrement_value = current_value - 1;
// Decrement and try to store.
if (!monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(decrement_value))) {
if (!monitor.ExclusiveWrite32(current_core, GetInteger(address),
static_cast<u32>(decrement_value))) {
// If we failed to store, try again.
DecrementIfLessThan(system, out, address, value);
}
@@ -57,7 +60,8 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
return true;
}
bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) {
bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value,
s32 new_value) {
auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
@@ -67,14 +71,16 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32
// TODO(bunnei): We should call CanAccessAtomic(..) here.
// Load the value from the address.
const s32 current_value = static_cast<s32>(monitor.ExclusiveRead32(current_core, address));
const s32 current_value =
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
// Compare it to the desired one.
if (current_value == value) {
// If equal, we want to try to write the new value.
// Try to store.
if (!monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(new_value))) {
if (!monitor.ExclusiveWrite32(current_core, GetInteger(address),
static_cast<u32>(new_value))) {
// If we failed to store, try again.
UpdateIfEqual(system, out, address, value, new_value);
}
@@ -90,8 +96,8 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32
class ThreadQueueImplForKAddressArbiter final : public KThreadQueue {
public:
explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t)
: KThreadQueue(kernel_), m_tree(t) {}
explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel, KAddressArbiter::ThreadTree* t)
: KThreadQueue(kernel), m_tree(t) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// If the thread is waiting on an address arbiter, remove it from the tree.
@@ -105,19 +111,19 @@ public:
}
private:
KAddressArbiter::ThreadTree* m_tree;
KAddressArbiter::ThreadTree* m_tree{};
};
} // namespace
Result KAddressArbiter::Signal(VAddr addr, s32 count) {
Result KAddressArbiter::Signal(uint64_t addr, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
KScopedSchedulerLock sl(kernel);
KScopedSchedulerLock sl(m_kernel);
auto it = thread_tree.nfind_key({addr, -1});
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
auto it = m_tree.nfind_key({addr, -1});
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetAddressArbiterKey() == addr)) {
// End the thread's wait.
KThread* target_thread = std::addressof(*it);
@@ -126,31 +132,27 @@ Result KAddressArbiter::Signal(VAddr addr, s32 count) {
ASSERT(target_thread->IsWaitingForAddressArbiter());
target_thread->ClearAddressArbiter();
it = thread_tree.erase(it);
it = m_tree.erase(it);
++num_waiters;
}
}
return ResultSuccess;
R_SUCCEED();
}
Result KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count) {
Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
KScopedSchedulerLock sl(kernel);
KScopedSchedulerLock sl(m_kernel);
// Check the userspace value.
s32 user_value{};
if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) {
LOG_ERROR(Kernel, "Invalid current memory!");
return ResultInvalidCurrentMemory;
}
if (user_value != value) {
return ResultInvalidState;
}
R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1),
ResultInvalidCurrentMemory);
R_UNLESS(user_value == value, ResultInvalidState);
auto it = thread_tree.nfind_key({addr, -1});
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
auto it = m_tree.nfind_key({addr, -1});
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetAddressArbiterKey() == addr)) {
// End the thread's wait.
KThread* target_thread = std::addressof(*it);
@@ -159,33 +161,33 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 cou
ASSERT(target_thread->IsWaitingForAddressArbiter());
target_thread->ClearAddressArbiter();
it = thread_tree.erase(it);
it = m_tree.erase(it);
++num_waiters;
}
}
return ResultSuccess;
R_SUCCEED();
}
Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count) {
Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32 value, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
[[maybe_unused]] const KScopedSchedulerLock sl(kernel);
KScopedSchedulerLock sl(m_kernel);
auto it = thread_tree.nfind_key({addr, -1});
auto it = m_tree.nfind_key({addr, -1});
// Determine the updated value.
s32 new_value{};
if (count <= 0) {
if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
if (it != m_tree.end() && it->GetAddressArbiterKey() == addr) {
new_value = value - 2;
} else {
new_value = value + 1;
}
} else {
if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
if (it != m_tree.end() && it->GetAddressArbiterKey() == addr) {
auto tmp_it = it;
s32 tmp_num_waiters{};
while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) {
while (++tmp_it != m_tree.end() && tmp_it->GetAddressArbiterKey() == addr) {
if (tmp_num_waiters++ >= count) {
break;
}
@@ -205,20 +207,15 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 val
s32 user_value{};
bool succeeded{};
if (value != new_value) {
succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value);
succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value);
} else {
succeeded = ReadFromUser(system, &user_value, addr);
succeeded = ReadFromUser(m_system, std::addressof(user_value), addr);
}
if (!succeeded) {
LOG_ERROR(Kernel, "Invalid current memory!");
return ResultInvalidCurrentMemory;
}
if (user_value != value) {
return ResultInvalidState;
}
R_UNLESS(succeeded, ResultInvalidCurrentMemory);
R_UNLESS(user_value == value, ResultInvalidState);
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetAddressArbiterKey() == addr)) {
// End the thread's wait.
KThread* target_thread = std::addressof(*it);
@@ -227,57 +224,57 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 val
ASSERT(target_thread->IsWaitingForAddressArbiter());
target_thread->ClearAddressArbiter();
it = thread_tree.erase(it);
it = m_tree.erase(it);
++num_waiters;
}
}
return ResultSuccess;
R_SUCCEED();
}
Result KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement, s64 timeout) {
// Prepare to wait.
KThread* cur_thread = GetCurrentThreadPointer(kernel);
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
KHardwareTimer* timer{};
ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
ThreadQueueImplForKAddressArbiter wait_queue(m_kernel, std::addressof(m_tree));
{
KScopedSchedulerLockAndSleep slp{kernel, std::addressof(timer), cur_thread, timeout};
KScopedSchedulerLockAndSleep slp{m_kernel, std::addressof(timer), cur_thread, timeout};
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
return ResultTerminationRequested;
R_THROW(ResultTerminationRequested);
}
// Read the value from userspace.
s32 user_value{};
bool succeeded{};
if (decrement) {
succeeded = DecrementIfLessThan(system, &user_value, addr, value);
succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value);
} else {
succeeded = ReadFromUser(system, &user_value, addr);
succeeded = ReadFromUser(m_system, std::addressof(user_value), addr);
}
if (!succeeded) {
slp.CancelSleep();
return ResultInvalidCurrentMemory;
R_THROW(ResultInvalidCurrentMemory);
}
// Check that the value is less than the specified one.
if (user_value >= value) {
slp.CancelSleep();
return ResultInvalidState;
R_THROW(ResultInvalidState);
}
// Check that the timeout is non-zero.
if (timeout == 0) {
slp.CancelSleep();
return ResultTimedOut;
R_THROW(ResultTimedOut);
}
// Set the arbiter.
cur_thread->SetAddressArbiter(&thread_tree, addr);
thread_tree.insert(*cur_thread);
cur_thread->SetAddressArbiter(std::addressof(m_tree), addr);
m_tree.insert(*cur_thread);
// Wait for the thread to finish.
wait_queue.SetHardwareTimer(timer);
@@ -289,43 +286,43 @@ Result KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s6
return cur_thread->GetWaitResult();
}
Result KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
Result KAddressArbiter::WaitIfEqual(uint64_t addr, s32 value, s64 timeout) {
// Prepare to wait.
KThread* cur_thread = GetCurrentThreadPointer(kernel);
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
KHardwareTimer* timer{};
ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
ThreadQueueImplForKAddressArbiter wait_queue(m_kernel, std::addressof(m_tree));
{
KScopedSchedulerLockAndSleep slp{kernel, std::addressof(timer), cur_thread, timeout};
KScopedSchedulerLockAndSleep slp{m_kernel, std::addressof(timer), cur_thread, timeout};
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
return ResultTerminationRequested;
R_THROW(ResultTerminationRequested);
}
// Read the value from userspace.
s32 user_value{};
if (!ReadFromUser(system, &user_value, addr)) {
if (!ReadFromUser(m_system, std::addressof(user_value), addr)) {
slp.CancelSleep();
return ResultInvalidCurrentMemory;
R_THROW(ResultInvalidCurrentMemory);
}
// Check that the value is equal.
if (value != user_value) {
slp.CancelSleep();
return ResultInvalidState;
R_THROW(ResultInvalidState);
}
// Check that the timeout is non-zero.
if (timeout == 0) {
slp.CancelSleep();
return ResultTimedOut;
R_THROW(ResultTimedOut);
}
// Set the arbiter.
cur_thread->SetAddressArbiter(&thread_tree, addr);
thread_tree.insert(*cur_thread);
cur_thread->SetAddressArbiter(std::addressof(m_tree), addr);
m_tree.insert(*cur_thread);
// Wait for the thread to finish.
wait_queue.SetHardwareTimer(timer);

View File

@@ -22,47 +22,46 @@ class KAddressArbiter {
public:
using ThreadTree = KConditionVariable::ThreadTree;
explicit KAddressArbiter(Core::System& system_);
explicit KAddressArbiter(Core::System& system);
~KAddressArbiter();
[[nodiscard]] Result SignalToAddress(VAddr addr, Svc::SignalType type, s32 value, s32 count) {
Result SignalToAddress(uint64_t addr, Svc::SignalType type, s32 value, s32 count) {
switch (type) {
case Svc::SignalType::Signal:
return Signal(addr, count);
R_RETURN(this->Signal(addr, count));
case Svc::SignalType::SignalAndIncrementIfEqual:
return SignalAndIncrementIfEqual(addr, value, count);
R_RETURN(this->SignalAndIncrementIfEqual(addr, value, count));
case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual:
return SignalAndModifyByWaitingCountIfEqual(addr, value, count);
R_RETURN(this->SignalAndModifyByWaitingCountIfEqual(addr, value, count));
default:
UNREACHABLE();
}
ASSERT(false);
return ResultUnknown;
}
[[nodiscard]] Result WaitForAddress(VAddr addr, Svc::ArbitrationType type, s32 value,
s64 timeout) {
Result WaitForAddress(uint64_t addr, Svc::ArbitrationType type, s32 value, s64 timeout) {
switch (type) {
case Svc::ArbitrationType::WaitIfLessThan:
return WaitIfLessThan(addr, value, false, timeout);
R_RETURN(WaitIfLessThan(addr, value, false, timeout));
case Svc::ArbitrationType::DecrementAndWaitIfLessThan:
return WaitIfLessThan(addr, value, true, timeout);
R_RETURN(WaitIfLessThan(addr, value, true, timeout));
case Svc::ArbitrationType::WaitIfEqual:
return WaitIfEqual(addr, value, timeout);
R_RETURN(WaitIfEqual(addr, value, timeout));
default:
UNREACHABLE();
}
ASSERT(false);
return ResultUnknown;
}
private:
[[nodiscard]] Result Signal(VAddr addr, s32 count);
[[nodiscard]] Result SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count);
[[nodiscard]] Result SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count);
[[nodiscard]] Result WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout);
[[nodiscard]] Result WaitIfEqual(VAddr addr, s32 value, s64 timeout);
Result Signal(uint64_t addr, s32 count);
Result SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32 count);
Result SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32 value, s32 count);
Result WaitIfLessThan(uint64_t addr, s32 value, bool decrement, s64 timeout);
Result WaitIfEqual(uint64_t addr, s32 value, s64 timeout);
ThreadTree thread_tree;
Core::System& system;
KernelCore& kernel;
private:
ThreadTree m_tree;
Core::System& m_system;
KernelCore& m_kernel;
};
} // namespace Kernel

View File

@@ -13,40 +13,40 @@ class KAffinityMask {
public:
constexpr KAffinityMask() = default;
[[nodiscard]] constexpr u64 GetAffinityMask() const {
return this->mask;
constexpr u64 GetAffinityMask() const {
return m_mask;
}
constexpr void SetAffinityMask(u64 new_mask) {
ASSERT((new_mask & ~AllowedAffinityMask) == 0);
this->mask = new_mask;
m_mask = new_mask;
}
[[nodiscard]] constexpr bool GetAffinity(s32 core) const {
return (this->mask & GetCoreBit(core)) != 0;
constexpr bool GetAffinity(s32 core) const {
return (m_mask & GetCoreBit(core)) != 0;
}
constexpr void SetAffinity(s32 core, bool set) {
if (set) {
this->mask |= GetCoreBit(core);
m_mask |= GetCoreBit(core);
} else {
this->mask &= ~GetCoreBit(core);
m_mask &= ~GetCoreBit(core);
}
}
constexpr void SetAll() {
this->mask = AllowedAffinityMask;
m_mask = AllowedAffinityMask;
}
private:
[[nodiscard]] static constexpr u64 GetCoreBit(s32 core) {
static constexpr u64 GetCoreBit(s32 core) {
ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
return (1ULL << core);
}
static constexpr u64 AllowedAffinityMask = (1ULL << Core::Hardware::NUM_CPU_CORES) - 1;
u64 mask{};
u64 m_mask{};
};
} // namespace Kernel

View File

@@ -12,11 +12,11 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) {
}
void KAutoObject::RegisterWithKernel() {
kernel.RegisterKernelObject(this);
m_kernel.RegisterKernelObject(this);
}
void KAutoObject::UnregisterWithKernel() {
kernel.UnregisterKernelObject(this);
m_kernel.UnregisterKernelObject(this);
}
} // namespace Kernel

View File

@@ -80,7 +80,7 @@ private:
KERNEL_AUTOOBJECT_TRAITS_IMPL(KAutoObject, KAutoObject, const);
public:
explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {
explicit KAutoObject(KernelCore& kernel) : m_kernel(kernel) {
RegisterWithKernel();
}
virtual ~KAutoObject() = default;
@@ -164,17 +164,12 @@ public:
}
}
const std::string& GetName() const {
return name;
}
private:
void RegisterWithKernel();
void UnregisterWithKernel();
protected:
KernelCore& kernel;
std::string name;
KernelCore& m_kernel;
private:
std::atomic<u32> m_ref_count{};
@@ -184,7 +179,7 @@ class KAutoObjectWithListContainer;
class KAutoObjectWithList : public KAutoObject, public boost::intrusive::set_base_hook<> {
public:
explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {}
explicit KAutoObjectWithList(KernelCore& kernel) : KAutoObject(kernel) {}
static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) {
const u64 lid = lhs.GetId();
@@ -200,7 +195,7 @@ public:
}
friend bool operator<(const KAutoObjectWithList& left, const KAutoObjectWithList& right) {
return &left < &right;
return KAutoObjectWithList::Compare(left, right) < 0;
}
public:
@@ -208,10 +203,6 @@ public:
return reinterpret_cast<u64>(this);
}
virtual const std::string& GetName() const {
return name;
}
private:
friend class KAutoObjectWithListContainer;
};

View File

@@ -11,7 +11,7 @@
namespace Kernel {
Result KCapabilities::InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table) {
Result KCapabilities::InitializeForKip(std::span<const u32> kern_caps, KPageTable* page_table) {
// We're initializing an initial process.
m_svc_access_flags.reset();
m_irq_access_flags.reset();

View File

@@ -22,7 +22,7 @@ class KCapabilities {
public:
constexpr explicit KCapabilities() = default;
Result InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table);
Result InitializeForKip(std::span<const u32> kern_caps, KPageTable* page_table);
Result InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table);
static Result CheckCapabilities(KernelCore& kernel, std::span<const u32> user_caps);

View File

@@ -11,26 +11,21 @@
namespace Kernel {
KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KClientPort::~KClientPort() = default;
void KClientPort::Initialize(KPort* parent_port_, s32 max_sessions_, std::string&& name_) {
void KClientPort::Initialize(KPort* parent, s32 max_sessions) {
// Set member variables.
num_sessions = 0;
peak_sessions = 0;
parent = parent_port_;
max_sessions = max_sessions_;
name = std::move(name_);
m_num_sessions = 0;
m_peak_sessions = 0;
m_parent = parent;
m_max_sessions = max_sessions;
}
void KClientPort::OnSessionFinalized() {
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// This might happen if a session was improperly used with this port.
ASSERT_MSG(num_sessions > 0, "num_sessions is invalid");
const auto prev = num_sessions--;
if (prev == max_sessions) {
if (const auto prev = m_num_sessions--; prev == m_max_sessions) {
this->NotifyAvailable();
}
}
@@ -47,81 +42,81 @@ bool KClientPort::IsServerClosed() const {
void KClientPort::Destroy() {
// Note with our parent that we're closed.
parent->OnClientClosed();
m_parent->OnClientClosed();
// Close our reference to our parent.
parent->Close();
m_parent->Close();
}
bool KClientPort::IsSignaled() const {
return num_sessions < max_sessions;
return m_num_sessions.load() < m_max_sessions;
}
Result KClientPort::CreateSession(KClientSession** out) {
// Declare the session we're going to allocate.
KSession* session{};
// Reserve a new session from the resource limit.
//! FIXME: we are reserving this from the wrong resource limit!
KScopedResourceReservation session_reservation(kernel.ApplicationProcess()->GetResourceLimit(),
LimitableResource::SessionCountMax);
KScopedResourceReservation session_reservation(
m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
// Allocate a session normally.
session = KSession::Create(m_kernel);
// Check that we successfully created a session.
R_UNLESS(session != nullptr, ResultOutOfResource);
// Update the session counts.
{
ON_RESULT_FAILURE {
session->Close();
};
// Atomically increment the number of sessions.
s32 new_sessions{};
{
const auto max = max_sessions;
auto cur_sessions = num_sessions.load(std::memory_order_acquire);
const auto max = m_max_sessions;
auto cur_sessions = m_num_sessions.load(std::memory_order_acquire);
do {
R_UNLESS(cur_sessions < max, ResultOutOfSessions);
new_sessions = cur_sessions + 1;
} while (!num_sessions.compare_exchange_weak(cur_sessions, new_sessions,
std::memory_order_relaxed));
} while (!m_num_sessions.compare_exchange_weak(cur_sessions, new_sessions,
std::memory_order_relaxed));
}
// Atomically update the peak session tracking.
{
auto peak = peak_sessions.load(std::memory_order_acquire);
auto peak = m_peak_sessions.load(std::memory_order_acquire);
do {
if (peak >= new_sessions) {
break;
}
} while (!peak_sessions.compare_exchange_weak(peak, new_sessions,
std::memory_order_relaxed));
} while (!m_peak_sessions.compare_exchange_weak(peak, new_sessions,
std::memory_order_relaxed));
}
}
// Create a new session.
KSession* session = KSession::Create(kernel);
if (session == nullptr) {
// Decrement the session count.
const auto prev = num_sessions--;
if (prev == max_sessions) {
this->NotifyAvailable();
}
return ResultOutOfResource;
}
// Initialize the session.
session->Initialize(this, parent->GetName());
session->Initialize(this, m_parent->GetName());
// Commit the session reservation.
session_reservation.Commit();
// Register the session.
KSession::Register(kernel, session);
auto session_guard = SCOPE_GUARD({
KSession::Register(m_kernel, session);
ON_RESULT_FAILURE {
session->GetClientSession().Close();
session->GetServerSession().Close();
});
};
// Enqueue the session with our parent.
R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession())));
R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession())));
// We succeeded, so set the output.
session_guard.Cancel();
*out = std::addressof(session->GetClientSession());
return ResultSuccess;
R_SUCCEED();
}
} // namespace Kernel

View File

@@ -4,7 +4,6 @@
#pragma once
#include <memory>
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/k_synchronization_object.h"
@@ -20,28 +19,28 @@ class KClientPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
public:
explicit KClientPort(KernelCore& kernel_);
explicit KClientPort(KernelCore& kernel);
~KClientPort() override;
void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
void Initialize(KPort* parent, s32 max_sessions);
void OnSessionFinalized();
void OnServerClosed();
const KPort* GetParent() const {
return parent;
return m_parent;
}
KPort* GetParent() {
return parent;
return m_parent;
}
s32 GetNumSessions() const {
return num_sessions;
return m_num_sessions;
}
s32 GetPeakSessions() const {
return peak_sessions;
return m_peak_sessions;
}
s32 GetMaxSessions() const {
return max_sessions;
return m_max_sessions;
}
bool IsLight() const;
@@ -54,10 +53,10 @@ public:
Result CreateSession(KClientSession** out);
private:
std::atomic<s32> num_sessions{};
std::atomic<s32> peak_sessions{};
s32 max_sessions{};
KPort* parent{};
std::atomic<s32> m_num_sessions{};
std::atomic<s32> m_peak_sessions{};
s32 m_max_sessions{};
KPort* m_parent{};
};
} // namespace Kernel

View File

@@ -12,28 +12,28 @@ namespace Kernel {
static constexpr u32 MessageBufferSize = 0x100;
KClientSession::KClientSession(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_} {}
KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
KClientSession::~KClientSession() = default;
void KClientSession::Destroy() {
parent->OnClientClosed();
parent->Close();
m_parent->OnClientClosed();
m_parent->Close();
}
void KClientSession::OnServerClosed() {}
Result KClientSession::SendSyncRequest() {
// Create a session request.
KSessionRequest* request = KSessionRequest::Create(kernel);
KSessionRequest* request = KSessionRequest::Create(m_kernel);
R_UNLESS(request != nullptr, ResultOutOfResource);
SCOPE_EXIT({ request->Close(); });
// Initialize the request.
request->Initialize(nullptr, GetCurrentThread(kernel).GetTLSAddress(), MessageBufferSize);
request->Initialize(nullptr, GetInteger(GetCurrentThread(m_kernel).GetTlsAddress()),
MessageBufferSize);
// Send the request.
return parent->GetServerSession().OnRequest(request);
R_RETURN(m_parent->GetServerSession().OnRequest(request));
}
} // namespace Kernel

View File

@@ -30,20 +30,19 @@ class KClientSession final
KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject);
public:
explicit KClientSession(KernelCore& kernel_);
explicit KClientSession(KernelCore& kernel);
~KClientSession() override;
void Initialize(KSession* parent_session_, std::string&& name_) {
void Initialize(KSession* parent) {
// Set member variables.
parent = parent_session_;
name = std::move(name_);
m_parent = parent;
}
void Destroy() override;
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
static void PostDestroy(uintptr_t arg) {}
KSession* GetParent() const {
return parent;
return m_parent;
}
Result SendSyncRequest();
@@ -51,7 +50,7 @@ public:
void OnServerClosed();
private:
KSession* parent{};
KSession* m_parent{};
};
} // namespace Kernel

View File

@@ -16,18 +16,19 @@
namespace Kernel {
KCodeMemory::KCodeMemory(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {}
KCodeMemory::KCodeMemory(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock(kernel) {}
Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) {
Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, KProcessAddress addr,
size_t size) {
// Set members.
m_owner = GetCurrentProcessPointer(kernel);
m_owner = GetCurrentProcessPointer(m_kernel);
// Get the owner page table.
auto& page_table = m_owner->PageTable();
// Construct the page group.
m_page_group.emplace(kernel, page_table.GetBlockInfoManager());
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
// Lock the memory.
R_TRY(page_table.LockForCodeMemory(std::addressof(*m_page_group), addr, size))
@@ -45,7 +46,7 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si
m_is_mapped = false;
// We succeeded.
return ResultSuccess;
R_SUCCEED();
}
void KCodeMemory::Finalize() {
@@ -63,7 +64,7 @@ void KCodeMemory::Finalize() {
m_owner->Close();
}
Result KCodeMemory::Map(VAddr address, size_t size) {
Result KCodeMemory::Map(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -74,16 +75,16 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
R_UNLESS(!m_is_mapped, ResultInvalidState);
// Map the memory.
R_TRY(GetCurrentProcess(kernel).PageTable().MapPageGroup(
R_TRY(GetCurrentProcess(m_kernel).PageTable().MapPageGroup(
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
m_is_mapped = true;
return ResultSuccess;
R_SUCCEED();
}
Result KCodeMemory::Unmap(VAddr address, size_t size) {
Result KCodeMemory::Unmap(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -91,16 +92,16 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(GetCurrentProcess(kernel).PageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::CodeOut));
R_TRY(GetCurrentProcess(m_kernel).PageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::CodeOut));
// Mark ourselves as unmapped.
m_is_mapped = false;
return ResultSuccess;
R_SUCCEED();
}
Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
Result KCodeMemory::MapToOwner(KProcessAddress address, size_t size, Svc::MemoryPermission perm) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -131,10 +132,10 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission
// Mark ourselves as mapped.
m_is_owner_mapped = true;
return ResultSuccess;
R_SUCCEED();
}
Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
Result KCodeMemory::UnmapFromOwner(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -147,7 +148,7 @@ Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
// Mark ourselves as unmapped.
m_is_owner_mapped = false;
return ResultSuccess;
R_SUCCEED();
}
} // namespace Kernel

View File

@@ -5,12 +5,12 @@
#include <optional>
#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
@@ -29,25 +29,25 @@ class KCodeMemory final
KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject);
public:
explicit KCodeMemory(KernelCore& kernel_);
explicit KCodeMemory(KernelCore& kernel);
Result Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
Result Initialize(Core::DeviceMemory& device_memory, KProcessAddress address, size_t size);
void Finalize() override;
Result Map(VAddr address, size_t size);
Result Unmap(VAddr address, size_t size);
Result MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
Result UnmapFromOwner(VAddr address, size_t size);
Result Map(KProcessAddress address, size_t size);
Result Unmap(KProcessAddress address, size_t size);
Result MapToOwner(KProcessAddress address, size_t size, Svc::MemoryPermission perm);
Result UnmapFromOwner(KProcessAddress address, size_t size);
bool IsInitialized() const override {
return m_is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
static void PostDestroy(uintptr_t arg) {}
KProcess* GetOwner() const override {
return m_owner;
}
VAddr GetSourceAddress() const {
KProcessAddress GetSourceAddress() const {
return m_address;
}
size_t GetSize() const {
@@ -57,7 +57,7 @@ public:
private:
std::optional<KPageGroup> m_page_group{};
KProcess* m_owner{};
VAddr m_address{};
KProcessAddress m_address{};
KLightLock m_lock;
bool m_is_initialized{};
bool m_is_owner_mapped{};

View File

@@ -4,7 +4,6 @@
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/hle/kernel/k_condition_variable.h"
#include "core/hle/kernel/k_linked_list.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
@@ -19,23 +18,23 @@ namespace Kernel {
namespace {
bool ReadFromUser(Core::System& system, u32* out, VAddr address) {
*out = system.Memory().Read32(address);
bool ReadFromUser(Core::System& system, u32* out, KProcessAddress address) {
*out = system.Memory().Read32(GetInteger(address));
return true;
}
bool WriteToUser(Core::System& system, VAddr address, const u32* p) {
system.Memory().Write32(address, *p);
bool WriteToUser(Core::System& system, KProcessAddress address, const u32* p) {
system.Memory().Write32(GetInteger(address), *p);
return true;
}
bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero,
bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero,
u32 new_orr_mask) {
auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
// Load the value from the address.
const auto expected = monitor.ExclusiveRead32(current_core, address);
const auto expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
// Orr in the new mask.
u32 value = expected | new_orr_mask;
@@ -46,7 +45,7 @@ bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero
}
// Try to store.
if (!monitor.ExclusiveWrite32(current_core, address, value)) {
if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) {
// If we failed to store, try again.
return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask);
}
@@ -58,8 +57,8 @@ bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero
class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue {
public:
explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_)
: KThreadQueue(kernel_) {}
explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel)
: KThreadQueue(kernel) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Remove the thread as a waiter from its owner.
@@ -76,8 +75,8 @@ private:
public:
explicit ThreadQueueImplForKConditionVariableWaitConditionVariable(
KernelCore& kernel_, KConditionVariable::ThreadTree* t)
: KThreadQueue(kernel_), m_tree(t) {}
KernelCore& kernel, KConditionVariable::ThreadTree* t)
: KThreadQueue(kernel), m_tree(t) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Remove the thread as a waiter from its owner.
@@ -98,17 +97,17 @@ public:
} // namespace
KConditionVariable::KConditionVariable(Core::System& system_)
: system{system_}, kernel{system.Kernel()} {}
KConditionVariable::KConditionVariable(Core::System& system)
: m_system{system}, m_kernel{system.Kernel()} {}
KConditionVariable::~KConditionVariable() = default;
Result KConditionVariable::SignalToAddress(VAddr addr) {
KThread* owner_thread = GetCurrentThreadPointer(kernel);
Result KConditionVariable::SignalToAddress(KProcessAddress addr) {
KThread* owner_thread = GetCurrentThreadPointer(m_kernel);
// Signal the address.
{
KScopedSchedulerLock sl(kernel);
KScopedSchedulerLock sl(m_kernel);
// Remove waiter thread.
bool has_waiters{};
@@ -129,7 +128,7 @@ Result KConditionVariable::SignalToAddress(VAddr addr) {
// Write the value to userspace.
Result result{ResultSuccess};
if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
if (WriteToUser(m_system, addr, std::addressof(next_value))) [[likely]] {
result = ResultSuccess;
} else {
result = ResultInvalidCurrentMemory;
@@ -144,27 +143,28 @@ Result KConditionVariable::SignalToAddress(VAddr addr) {
}
}
Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
KThread* cur_thread = GetCurrentThreadPointer(kernel);
ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel);
Result KConditionVariable::WaitForAddress(Handle handle, KProcessAddress addr, u32 value) {
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(m_kernel);
// Wait for the address.
KThread* owner_thread{};
{
KScopedSchedulerLock sl(kernel);
KScopedSchedulerLock sl(m_kernel);
// Check if the thread should terminate.
R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested);
// Read the tag from userspace.
u32 test_tag{};
R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory);
R_UNLESS(ReadFromUser(m_system, std::addressof(test_tag), addr),
ResultInvalidCurrentMemory);
// If the tag isn't the handle (with wait mask), we're done.
R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask));
// Get the lock owner thread.
owner_thread = GetCurrentProcess(kernel)
owner_thread = GetCurrentProcess(m_kernel)
.GetHandleTable()
.GetObjectWithoutPseudoHandle<KThread>(handle)
.ReleasePointerUnsafe();
@@ -177,22 +177,21 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value)
// Begin waiting.
cur_thread->BeginWait(std::addressof(wait_queue));
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
cur_thread->SetMutexWaitAddressForDebugging(addr);
}
// Close our reference to the owner thread, now that the wait is over.
owner_thread->Close();
// Get the wait result.
return cur_thread->GetWaitResult();
R_RETURN(cur_thread->GetWaitResult());
}
void KConditionVariable::SignalImpl(KThread* thread) {
// Check pre-conditions.
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Update the tag.
VAddr address = thread->GetAddressKey();
KProcessAddress address = thread->GetAddressKey();
u32 own_tag = thread->GetAddressKeyValue();
u32 prev_tag{};
@@ -204,7 +203,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
// TODO(bunnei): We should call CanAccessAtomic(..) here.
can_access = true;
if (can_access) [[likely]] {
UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag,
UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag,
Svc::HandleWaitMask);
}
}
@@ -215,7 +214,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
thread->EndWait(ResultSuccess);
} else {
// Get the previous owner.
KThread* owner_thread = GetCurrentProcess(kernel)
KThread* owner_thread = GetCurrentProcess(m_kernel)
.GetHandleTable()
.GetObjectWithoutPseudoHandle<KThread>(
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
@@ -240,14 +239,14 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
KScopedSchedulerLock sl(kernel);
KScopedSchedulerLock sl(m_kernel);
auto it = thread_tree.nfind_key({cv_key, -1});
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
auto it = m_tree.nfind_key({cv_key, -1});
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetConditionVariableKey() == cv_key)) {
KThread* target_thread = std::addressof(*it);
it = thread_tree.erase(it);
it = m_tree.erase(it);
target_thread->ClearConditionVariable();
this->SignalImpl(target_thread);
@@ -256,27 +255,27 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
}
// If we have no waiters, clear the has waiter flag.
if (it == thread_tree.end() || it->GetConditionVariableKey() != cv_key) {
if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) {
const u32 has_waiter_flag{};
WriteToUser(system, cv_key, std::addressof(has_waiter_flag));
WriteToUser(m_system, cv_key, std::addressof(has_waiter_flag));
}
}
}
Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
Result KConditionVariable::Wait(KProcessAddress addr, u64 key, u32 value, s64 timeout) {
// Prepare to wait.
KThread* cur_thread = GetCurrentThreadPointer(kernel);
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
KHardwareTimer* timer{};
ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(
kernel, std::addressof(thread_tree));
ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(m_kernel,
std::addressof(m_tree));
{
KScopedSchedulerLockAndSleep slp(kernel, std::addressof(timer), cur_thread, timeout);
KScopedSchedulerLockAndSleep slp(m_kernel, std::addressof(timer), cur_thread, timeout);
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
return ResultTerminationRequested;
R_THROW(ResultTerminationRequested);
}
// Update the value and process for the next owner.
@@ -302,14 +301,14 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
// Write to the cv key.
{
const u32 has_waiter_flag = 1;
WriteToUser(system, key, std::addressof(has_waiter_flag));
// TODO(bunnei): We should call DataMemoryBarrier(..) here.
WriteToUser(m_system, key, std::addressof(has_waiter_flag));
std::atomic_thread_fence(std::memory_order_seq_cst);
}
// Write the value to userspace.
if (!WriteToUser(system, addr, std::addressof(next_value))) {
if (!WriteToUser(m_system, addr, std::addressof(next_value))) {
slp.CancelSleep();
return ResultInvalidCurrentMemory;
R_THROW(ResultInvalidCurrentMemory);
}
}
@@ -317,18 +316,17 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
R_UNLESS(timeout != 0, ResultTimedOut);
// Update condition variable tracking.
cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value);
thread_tree.insert(*cur_thread);
cur_thread->SetConditionVariable(std::addressof(m_tree), addr, key, value);
m_tree.insert(*cur_thread);
// Begin waiting.
wait_queue.SetHardwareTimer(timer);
cur_thread->BeginWait(std::addressof(wait_queue));
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
cur_thread->SetMutexWaitAddressForDebugging(addr);
}
// Get the wait result.
return cur_thread->GetWaitResult();
R_RETURN(cur_thread->GetWaitResult());
}
} // namespace Kernel

View File

@@ -4,10 +4,10 @@
#pragma once
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
@@ -21,36 +21,36 @@ class KConditionVariable {
public:
using ThreadTree = typename KThread::ConditionVariableThreadTreeType;
explicit KConditionVariable(Core::System& system_);
explicit KConditionVariable(Core::System& system);
~KConditionVariable();
// Arbitration
[[nodiscard]] Result SignalToAddress(VAddr addr);
[[nodiscard]] Result WaitForAddress(Handle handle, VAddr addr, u32 value);
Result SignalToAddress(KProcessAddress addr);
Result WaitForAddress(Handle handle, KProcessAddress addr, u32 value);
// Condition variable
void Signal(u64 cv_key, s32 count);
[[nodiscard]] Result Wait(VAddr addr, u64 key, u32 value, s64 timeout);
Result Wait(KProcessAddress addr, u64 key, u32 value, s64 timeout);
private:
void SignalImpl(KThread* thread);
ThreadTree thread_tree;
Core::System& system;
KernelCore& kernel;
private:
Core::System& m_system;
KernelCore& m_kernel;
ThreadTree m_tree{};
};
inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
inline void BeforeUpdatePriority(KernelCore& kernel, KConditionVariable::ThreadTree* tree,
KThread* thread) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
tree->erase(tree->iterator_to(*thread));
}
inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
inline void AfterUpdatePriority(KernelCore& kernel, KConditionVariable::ThreadTree* tree,
KThread* thread) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
tree->insert(*thread);
}

View File

@@ -12,9 +12,9 @@ class KDebug final : public KAutoObjectWithSlabHeapAndContainer<KDebug, KAutoObj
KERNEL_AUTOOBJECT_TRAITS(KDebug, KAutoObject);
public:
explicit KDebug(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
explicit KDebug(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
static void PostDestroy(uintptr_t arg) {}
};
} // namespace Kernel

View File

@@ -9,8 +9,8 @@
namespace Kernel {
KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer(kernel_), m_lock(kernel_), m_is_initialized(false) {}
KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer(kernel), m_lock(kernel), m_is_initialized(false) {}
KDeviceAddressSpace::~KDeviceAddressSpace() = default;
void KDeviceAddressSpace::Initialize() {
@@ -54,8 +54,8 @@ Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) {
R_SUCCEED();
}
Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, size_t size,
u64 device_address, u32 option, bool is_aligned) {
Result KDeviceAddressSpace::Map(KPageTable* page_table, KProcessAddress process_address,
size_t size, u64 device_address, u32 option, bool is_aligned) {
// Check that the address falls within the space.
R_UNLESS((m_space_address <= device_address &&
device_address + size - 1 <= m_space_address + m_space_size - 1),
@@ -113,8 +113,8 @@ Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, s
R_SUCCEED();
}
Result KDeviceAddressSpace::Unmap(KPageTable* page_table, VAddr process_address, size_t size,
u64 device_address) {
Result KDeviceAddressSpace::Unmap(KPageTable* page_table, KProcessAddress process_address,
size_t size, u64 device_address) {
// Check that the address falls within the space.
R_UNLESS((m_space_address <= device_address &&
device_address + size - 1 <= m_space_address + m_space_size - 1),

View File

@@ -5,8 +5,8 @@
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
@@ -31,23 +31,24 @@ public:
Result Attach(Svc::DeviceName device_name);
Result Detach(Svc::DeviceName device_name);
Result MapByForce(KPageTable* page_table, VAddr process_address, size_t size,
Result MapByForce(KPageTable* page_table, KProcessAddress process_address, size_t size,
u64 device_address, u32 option) {
R_RETURN(this->Map(page_table, process_address, size, device_address, option, false));
}
Result MapAligned(KPageTable* page_table, VAddr process_address, size_t size,
Result MapAligned(KPageTable* page_table, KProcessAddress process_address, size_t size,
u64 device_address, u32 option) {
R_RETURN(this->Map(page_table, process_address, size, device_address, option, true));
}
Result Unmap(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address);
Result Unmap(KPageTable* page_table, KProcessAddress process_address, size_t size,
u64 device_address);
static void Initialize();
private:
Result Map(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address,
u32 option, bool is_aligned);
Result Map(KPageTable* page_table, KProcessAddress process_address, size_t size,
u64 device_address, u32 option, bool is_aligned);
private:
KLightLock m_lock;

View File

@@ -6,9 +6,9 @@
#include <vector>
#include "common/alignment.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_page_bitmap.h"
#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
#include "core/hle/kernel/svc_results.h"
@@ -26,23 +26,23 @@ public:
KDynamicPageManager() = default;
template <typename T>
T* GetPointer(VAddr addr) {
T* GetPointer(KVirtualAddress addr) {
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
}
template <typename T>
const T* GetPointer(VAddr addr) const {
const T* GetPointer(KVirtualAddress addr) const {
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
}
Result Initialize(VAddr memory, size_t size, size_t align) {
Result Initialize(KVirtualAddress memory, size_t size, size_t align) {
// We need to have positive size.
R_UNLESS(size > 0, ResultOutOfMemory);
m_backing_memory.resize(size);
// Set addresses.
m_address = memory;
m_aligned_address = Common::AlignDown(memory, align);
m_aligned_address = Common::AlignDown(GetInteger(memory), align);
// Calculate extents.
const size_t managed_size = m_address + size - m_aligned_address;
@@ -79,7 +79,7 @@ public:
R_SUCCEED();
}
VAddr GetAddress() const {
KVirtualAddress GetAddress() const {
return m_address;
}
size_t GetSize() const {
@@ -145,7 +145,8 @@ public:
KScopedSpinLock lk(m_lock);
// Set the bit for the free page.
size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_aligned_address) / sizeof(PageBuffer);
size_t offset =
(reinterpret_cast<uint64_t>(pb) - GetInteger(m_aligned_address)) / sizeof(PageBuffer);
m_page_bitmap.SetBit(offset);
// Decrement our used count.
@@ -158,8 +159,8 @@ private:
size_t m_used{};
size_t m_peak{};
size_t m_count{};
VAddr m_address{};
VAddr m_aligned_address{};
KVirtualAddress m_address{};
KVirtualAddress m_aligned_address{};
size_t m_size{};
// TODO(bunnei): Back by host memory until we emulate kernel virtual address space.

View File

@@ -19,7 +19,7 @@ class KDynamicSlabHeap : protected impl::KSlabHeapImpl {
public:
constexpr KDynamicSlabHeap() = default;
constexpr VAddr GetAddress() const {
constexpr KVirtualAddress GetAddress() const {
return m_address;
}
constexpr size_t GetSize() const {
@@ -35,7 +35,7 @@ public:
return m_count.load();
}
constexpr bool IsInRange(VAddr addr) const {
constexpr bool IsInRange(KVirtualAddress addr) const {
return this->GetAddress() <= addr && addr <= this->GetAddress() + this->GetSize() - 1;
}
@@ -115,7 +115,7 @@ private:
std::atomic<size_t> m_used{};
std::atomic<size_t> m_peak{};
std::atomic<size_t> m_count{};
VAddr m_address{};
KVirtualAddress m_address{};
size_t m_size{};
};

View File

@@ -7,8 +7,8 @@
namespace Kernel {
KEvent::KEvent(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, m_readable_event{kernel_} {}
KEvent::KEvent(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_readable_event{kernel} {}
KEvent::~KEvent() = default;
@@ -36,7 +36,7 @@ void KEvent::Finalize() {
}
Result KEvent::Signal() {
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
R_SUCCEED_IF(m_readable_event_destroyed);
@@ -44,7 +44,7 @@ Result KEvent::Signal() {
}
Result KEvent::Clear() {
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
R_SUCCEED_IF(m_readable_event_destroyed);

View File

@@ -16,7 +16,7 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObj
KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject);
public:
explicit KEvent(KernelCore& kernel_);
explicit KEvent(KernelCore& kernel);
~KEvent() override;
void Initialize(KProcess* owner);

View File

@@ -13,9 +13,9 @@ namespace {
class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue {
public:
ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl,
ThreadQueueImplForKLightConditionVariable(KernelCore& kernel, KThread::WaiterList* wl,
bool term)
: KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {}
: KThreadQueue(kernel), m_wait_list(wl), m_allow_terminating_thread(term) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Only process waits if we're allowed to.
@@ -39,15 +39,15 @@ private:
void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
// Create thread queue.
KThread* owner = GetCurrentThreadPointer(kernel);
KThread* owner = GetCurrentThreadPointer(m_kernel);
KHardwareTimer* timer{};
ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list),
ThreadQueueImplForKLightConditionVariable wait_queue(m_kernel, std::addressof(m_wait_list),
allow_terminating_thread);
// Sleep the thread.
{
KScopedSchedulerLockAndSleep lk(kernel, std::addressof(timer), owner, timeout);
KScopedSchedulerLockAndSleep lk(m_kernel, std::addressof(timer), owner, timeout);
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep();
@@ -57,7 +57,7 @@ void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_ter
lock->Unlock();
// Add the thread to the queue.
wait_list.push_back(*owner);
m_wait_list.push_back(*owner);
// Begin waiting.
wait_queue.SetHardwareTimer(timer);
@@ -69,10 +69,10 @@ void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_ter
}
void KLightConditionVariable::Broadcast() {
KScopedSchedulerLock lk(kernel);
KScopedSchedulerLock lk(m_kernel);
// Signal all threads.
for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) {
for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it = m_wait_list.erase(it)) {
it->EndWait(ResultSuccess);
}
}

View File

@@ -13,13 +13,13 @@ class KLightLock;
class KLightConditionVariable {
public:
explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
explicit KLightConditionVariable(KernelCore& kernel) : m_kernel{kernel} {}
void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true);
void Broadcast();
private:
KernelCore& kernel;
KThread::WaiterList wait_list{};
KernelCore& m_kernel;
KThread::WaiterList m_wait_list{};
};
} // namespace Kernel

View File

@@ -13,7 +13,7 @@ namespace {
class ThreadQueueImplForKLightLock final : public KThreadQueue {
public:
explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {}
explicit ThreadQueueImplForKLightLock(KernelCore& kernel) : KThreadQueue(kernel) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Remove the thread as a waiter from its owner.
@@ -29,13 +29,13 @@ public:
} // namespace
void KLightLock::Lock() {
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel));
while (true) {
uintptr_t old_tag = tag.load(std::memory_order_relaxed);
uintptr_t old_tag = m_tag.load(std::memory_order_relaxed);
while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),
std::memory_order_acquire)) {
while (!m_tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),
std::memory_order_acquire)) {
}
if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) {
@@ -45,30 +45,30 @@ void KLightLock::Lock() {
}
void KLightLock::Unlock() {
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel));
uintptr_t expected = cur_thread;
if (!tag.compare_exchange_strong(expected, 0, std::memory_order_release)) {
if (!m_tag.compare_exchange_strong(expected, 0, std::memory_order_release)) {
this->UnlockSlowPath(cur_thread);
}
}
bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
ThreadQueueImplForKLightLock wait_queue(kernel);
ThreadQueueImplForKLightLock wait_queue(m_kernel);
// Pend the current thread waiting on the owner thread.
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// Ensure we actually have locking to do.
if (tag.load(std::memory_order_relaxed) != _owner) {
if (m_tag.load(std::memory_order_relaxed) != _owner) {
return false;
}
// Add the current thread as a waiter on the owner.
KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL);
cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
owner_thread->AddWaiter(cur_thread);
// Begin waiting to hold the lock.
@@ -87,12 +87,12 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
// Unlock.
{
KScopedSchedulerLock sl(kernel);
KScopedSchedulerLock sl(m_kernel);
// Get the next owner.
bool has_waiters;
KThread* next_owner = owner_thread->RemoveKernelWaiterByKey(
std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag)));
std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
// Pass the lock to the next owner.
uintptr_t next_tag = 0;
@@ -114,12 +114,13 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
}
// Write the new tag value.
tag.store(next_tag, std::memory_order_release);
m_tag.store(next_tag, std::memory_order_release);
}
}
bool KLightLock::IsLockedByCurrentThread() const {
return (tag | 1ULL) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)) | 1ULL);
return (m_tag.load() | 1ULL) ==
(reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel)) | 1ULL);
}
} // namespace Kernel

View File

@@ -13,7 +13,7 @@ class KernelCore;
class KLightLock {
public:
explicit KLightLock(KernelCore& kernel_) : kernel{kernel_} {}
explicit KLightLock(KernelCore& kernel) : m_kernel{kernel} {}
void Lock();
@@ -24,14 +24,14 @@ public:
void UnlockSlowPath(uintptr_t cur_thread);
bool IsLocked() const {
return tag != 0;
return m_tag.load() != 0;
}
bool IsLockedByCurrentThread() const;
private:
std::atomic<uintptr_t> tag{};
KernelCore& kernel;
std::atomic<uintptr_t> m_tag{};
KernelCore& m_kernel;
};
using KScopedLightLock = KScopedLock<KLightLock>;

View File

@@ -1,238 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <boost/intrusive/list.hpp>
#include "common/assert.h"
#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
class KernelCore;
class KLinkedListNode : public boost::intrusive::list_base_hook<>,
public KSlabAllocated<KLinkedListNode> {
public:
explicit KLinkedListNode(KernelCore&) {}
KLinkedListNode() = default;
void Initialize(void* it) {
m_item = it;
}
void* GetItem() const {
return m_item;
}
private:
void* m_item = nullptr;
};
template <typename T>
class KLinkedList : private boost::intrusive::list<KLinkedListNode> {
private:
using BaseList = boost::intrusive::list<KLinkedListNode>;
public:
template <bool Const>
class Iterator;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
template <bool Const>
class Iterator {
private:
using BaseIterator = BaseList::iterator;
friend class KLinkedList;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename KLinkedList::value_type;
using difference_type = typename KLinkedList::difference_type;
using pointer = std::conditional_t<Const, KLinkedList::const_pointer, KLinkedList::pointer>;
using reference =
std::conditional_t<Const, KLinkedList::const_reference, KLinkedList::reference>;
public:
explicit Iterator(BaseIterator it) : m_base_it(it) {}
pointer GetItem() const {
return static_cast<pointer>(m_base_it->GetItem());
}
bool operator==(const Iterator& rhs) const {
return m_base_it == rhs.m_base_it;
}
bool operator!=(const Iterator& rhs) const {
return !(*this == rhs);
}
pointer operator->() const {
return this->GetItem();
}
reference operator*() const {
return *this->GetItem();
}
Iterator& operator++() {
++m_base_it;
return *this;
}
Iterator& operator--() {
--m_base_it;
return *this;
}
Iterator operator++(int) {
const Iterator it{*this};
++(*this);
return it;
}
Iterator operator--(int) {
const Iterator it{*this};
--(*this);
return it;
}
operator Iterator<true>() const {
return Iterator<true>(m_base_it);
}
private:
BaseIterator m_base_it;
};
public:
constexpr KLinkedList(KernelCore& kernel_) : BaseList(), kernel{kernel_} {}
~KLinkedList() {
// Erase all elements.
for (auto it = begin(); it != end(); it = erase(it)) {
}
// Ensure we succeeded.
ASSERT(this->empty());
}
// Iterator accessors.
iterator begin() {
return iterator(BaseList::begin());
}
const_iterator begin() const {
return const_iterator(BaseList::begin());
}
iterator end() {
return iterator(BaseList::end());
}
const_iterator end() const {
return const_iterator(BaseList::end());
}
const_iterator cbegin() const {
return this->begin();
}
const_iterator cend() const {
return this->end();
}
reverse_iterator rbegin() {
return reverse_iterator(this->end());
}
const_reverse_iterator rbegin() const {
return const_reverse_iterator(this->end());
}
reverse_iterator rend() {
return reverse_iterator(this->begin());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(this->begin());
}
const_reverse_iterator crbegin() const {
return this->rbegin();
}
const_reverse_iterator crend() const {
return this->rend();
}
// Content management.
using BaseList::empty;
using BaseList::size;
reference back() {
return *(--this->end());
}
const_reference back() const {
return *(--this->end());
}
reference front() {
return *this->begin();
}
const_reference front() const {
return *this->begin();
}
iterator insert(const_iterator pos, reference ref) {
KLinkedListNode* new_node = KLinkedListNode::Allocate(kernel);
ASSERT(new_node != nullptr);
new_node->Initialize(std::addressof(ref));
return iterator(BaseList::insert(pos.m_base_it, *new_node));
}
void push_back(reference ref) {
this->insert(this->end(), ref);
}
void push_front(reference ref) {
this->insert(this->begin(), ref);
}
void pop_back() {
this->erase(--this->end());
}
void pop_front() {
this->erase(this->begin());
}
iterator erase(const iterator pos) {
KLinkedListNode* freed_node = std::addressof(*pos.m_base_it);
iterator ret = iterator(BaseList::erase(pos.m_base_it));
KLinkedListNode::Free(kernel, freed_node);
return ret;
}
private:
KernelCore& kernel;
};
} // namespace Kernel

View File

@@ -5,8 +5,8 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
#include "core/hle/kernel/svc_types.h"
@@ -282,7 +282,7 @@ class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>
private:
u16 m_device_disable_merge_left_count{};
u16 m_device_disable_merge_right_count{};
VAddr m_address{};
KProcessAddress m_address{};
size_t m_num_pages{};
KMemoryState m_memory_state{KMemoryState::None};
u16 m_ipc_lock_count{};
@@ -306,7 +306,7 @@ public:
}
public:
constexpr VAddr GetAddress() const {
constexpr KProcessAddress GetAddress() const {
return m_address;
}
@@ -318,11 +318,11 @@ public:
return this->GetNumPages() * PageSize;
}
constexpr VAddr GetEndAddress() const {
constexpr KProcessAddress GetEndAddress() const {
return this->GetAddress() + this->GetSize();
}
constexpr VAddr GetLastAddress() const {
constexpr KProcessAddress GetLastAddress() const {
return this->GetEndAddress() - 1;
}
@@ -348,7 +348,7 @@ public:
constexpr KMemoryInfo GetMemoryInfo() const {
return {
.m_address = this->GetAddress(),
.m_address = GetInteger(this->GetAddress()),
.m_size = this->GetSize(),
.m_state = m_memory_state,
.m_device_disable_merge_left_count = m_device_disable_merge_left_count,
@@ -366,12 +366,12 @@ public:
public:
explicit KMemoryBlock() = default;
constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
constexpr KMemoryBlock(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p,
KMemoryAttribute attr)
: Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), m_address(addr), m_num_pages(np),
m_memory_state(ms), m_permission(p), m_attribute(attr) {}
constexpr void Initialize(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
constexpr void Initialize(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p,
KMemoryAttribute attr) {
m_device_disable_merge_left_count = 0;
m_device_disable_merge_right_count = 0;
@@ -408,7 +408,7 @@ public:
KMemoryBlockDisableMergeAttribute::None;
}
constexpr bool Contains(VAddr addr) const {
constexpr bool Contains(KProcessAddress addr) const {
return this->GetAddress() <= addr && addr <= this->GetEndAddress();
}
@@ -443,10 +443,10 @@ public:
}
}
constexpr void Split(KMemoryBlock* block, VAddr addr) {
constexpr void Split(KMemoryBlock* block, KProcessAddress addr) {
ASSERT(this->GetAddress() < addr);
ASSERT(this->Contains(addr));
ASSERT(Common::IsAligned(addr, PageSize));
ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
block->m_address = m_address;
block->m_num_pages = (addr - this->GetAddress()) / PageSize;
@@ -471,8 +471,8 @@ public:
m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllRight);
}
constexpr void UpdateDeviceDisableMergeStateForShareLeft(
[[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
constexpr void UpdateDeviceDisableMergeStateForShareLeft(KMemoryPermission new_perm, bool left,
bool right) {
// New permission/right aren't used.
if (left) {
m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
@@ -482,8 +482,8 @@ public:
}
}
constexpr void UpdateDeviceDisableMergeStateForShareRight(
[[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
constexpr void UpdateDeviceDisableMergeStateForShareRight(KMemoryPermission new_perm, bool left,
bool right) {
// New permission/left aren't used.
if (right) {
m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
@@ -499,8 +499,7 @@ public:
this->UpdateDeviceDisableMergeStateForShareRight(new_perm, left, right);
}
constexpr void ShareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
bool right) {
constexpr void ShareToDevice(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must either be shared or have a zero lock count.
@@ -516,8 +515,8 @@ public:
this->UpdateDeviceDisableMergeStateForShare(new_perm, left, right);
}
constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(
[[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(KMemoryPermission new_perm,
bool left, bool right) {
// New permission/right aren't used.
if (left) {
@@ -536,8 +535,8 @@ public:
}
}
constexpr void UpdateDeviceDisableMergeStateForUnshareRight(
[[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
constexpr void UpdateDeviceDisableMergeStateForUnshareRight(KMemoryPermission new_perm,
bool left, bool right) {
// New permission/left aren't used.
if (right) {
@@ -556,8 +555,7 @@ public:
this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right);
}
constexpr void UnshareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
bool right) {
constexpr void UnshareToDevice(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must be shared.
@@ -575,8 +573,7 @@ public:
this->UpdateDeviceDisableMergeStateForUnshare(new_perm, left, right);
}
constexpr void UnshareToDeviceRight([[maybe_unused]] KMemoryPermission new_perm, bool left,
bool right) {
constexpr void UnshareToDeviceRight(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must be shared.
@@ -594,7 +591,7 @@ public:
this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right);
}
constexpr void LockForIpc(KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
constexpr void LockForIpc(KMemoryPermission new_perm, bool left, bool right) {
// We must either be locked or have a zero lock count.
ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::IpcLocked ||
m_ipc_lock_count == 0);
@@ -626,8 +623,7 @@ public:
}
}
constexpr void UnlockForIpc([[maybe_unused]] KMemoryPermission new_perm, bool left,
[[maybe_unused]] bool right) {
constexpr void UnlockForIpc(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must be locked.

View File

@@ -7,7 +7,8 @@ namespace Kernel {
KMemoryBlockManager::KMemoryBlockManager() = default;
Result KMemoryBlockManager::Initialize(VAddr st, VAddr nd, KMemoryBlockSlabManager* slab_manager) {
Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd,
KMemoryBlockSlabManager* slab_manager) {
// Allocate a block to encapsulate the address space, insert it into the tree.
KMemoryBlock* start_block = slab_manager->Allocate();
R_UNLESS(start_block != nullptr, ResultOutOfResource);
@@ -15,8 +16,8 @@ Result KMemoryBlockManager::Initialize(VAddr st, VAddr nd, KMemoryBlockSlabManag
// Set our start and end.
m_start_address = st;
m_end_address = nd;
ASSERT(Common::IsAligned(m_start_address, PageSize));
ASSERT(Common::IsAligned(m_end_address, PageSize));
ASSERT(Common::IsAligned(GetInteger(m_start_address), PageSize));
ASSERT(Common::IsAligned(GetInteger(m_end_address), PageSize));
// Initialize and insert the block.
start_block->Initialize(m_start_address, (m_end_address - m_start_address) / PageSize,
@@ -40,12 +41,13 @@ void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager,
ASSERT(m_memory_block_tree.empty());
}
VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, size_t region_num_pages,
size_t num_pages, size_t alignment, size_t offset,
size_t guard_pages) const {
KProcessAddress KMemoryBlockManager::FindFreeArea(KProcessAddress region_start,
size_t region_num_pages, size_t num_pages,
size_t alignment, size_t offset,
size_t guard_pages) const {
if (num_pages > 0) {
const VAddr region_end = region_start + region_num_pages * PageSize;
const VAddr region_last = region_end - 1;
const KProcessAddress region_end = region_start + region_num_pages * PageSize;
const KProcessAddress region_last = region_end - 1;
for (const_iterator it = this->FindIterator(region_start); it != m_memory_block_tree.cend();
it++) {
const KMemoryInfo info = it->GetMemoryInfo();
@@ -56,17 +58,19 @@ VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, size_t region_num_pa
continue;
}
VAddr area = (info.GetAddress() <= region_start) ? region_start : info.GetAddress();
KProcessAddress area =
(info.GetAddress() <= GetInteger(region_start)) ? region_start : info.GetAddress();
area += guard_pages * PageSize;
const VAddr offset_area = Common::AlignDown(area, alignment) + offset;
const KProcessAddress offset_area =
Common::AlignDown(GetInteger(area), alignment) + offset;
area = (area <= offset_area) ? offset_area : offset_area + alignment;
const VAddr area_end = area + num_pages * PageSize + guard_pages * PageSize;
const VAddr area_last = area_end - 1;
const KProcessAddress area_end = area + num_pages * PageSize + guard_pages * PageSize;
const KProcessAddress area_last = area_end - 1;
if (info.GetAddress() <= area && area < area_last && area_last <= region_last &&
area_last <= info.GetLastAddress()) {
if (info.GetAddress() <= GetInteger(area) && area < area_last &&
area_last <= region_last && area_last <= info.GetLastAddress()) {
return area;
}
}
@@ -76,7 +80,7 @@ VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, size_t region_num_pa
}
void KMemoryBlockManager::CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator* allocator,
VAddr address, size_t num_pages) {
KProcessAddress address, size_t num_pages) {
// Find the iterator now that we've updated.
iterator it = this->FindIterator(address);
if (address != m_start_address) {
@@ -104,18 +108,18 @@ void KMemoryBlockManager::CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator*
}
}
void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
size_t num_pages, KMemoryState state, KMemoryPermission perm,
KMemoryAttribute attr,
void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator,
KProcessAddress address, size_t num_pages, KMemoryState state,
KMemoryPermission perm, KMemoryAttribute attr,
KMemoryBlockDisableMergeAttribute set_disable_attr,
KMemoryBlockDisableMergeAttribute clear_disable_attr) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
ASSERT(Common::IsAligned(address, PageSize));
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT((attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
KMemoryAttribute::None);
VAddr cur_address = address;
KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
@@ -168,17 +172,17 @@ void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator,
}
void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator,
VAddr address, size_t num_pages, KMemoryState test_state,
KMemoryPermission test_perm, KMemoryAttribute test_attr,
KMemoryState state, KMemoryPermission perm,
KMemoryAttribute attr) {
KProcessAddress address, size_t num_pages,
KMemoryState test_state, KMemoryPermission test_perm,
KMemoryAttribute test_attr, KMemoryState state,
KMemoryPermission perm, KMemoryAttribute attr) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
ASSERT(Common::IsAligned(address, PageSize));
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT((attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
KMemoryAttribute::None);
VAddr cur_address = address;
KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
@@ -230,18 +234,18 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo
this->CoalesceForUpdate(allocator, address, num_pages);
}
void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
size_t num_pages, MemoryBlockLockFunction lock_func,
KMemoryPermission perm) {
void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator,
KProcessAddress address, size_t num_pages,
MemoryBlockLockFunction lock_func, KMemoryPermission perm) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
ASSERT(Common::IsAligned(address, PageSize));
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
VAddr cur_address = address;
KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
const VAddr end_address = address + (num_pages * PageSize);
const KProcessAddress end_address = address + (num_pages * PageSize);
while (remaining_pages > 0) {
const size_t remaining_size = remaining_pages * PageSize;

View File

@@ -7,9 +7,9 @@
#include <functional>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
@@ -85,9 +85,10 @@ public:
public:
KMemoryBlockManager();
using HostUnmapCallback = std::function<void(VAddr, u64)>;
using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>;
Result Initialize(VAddr st, VAddr nd, KMemoryBlockSlabManager* slab_manager);
Result Initialize(KProcessAddress st, KProcessAddress nd,
KMemoryBlockSlabManager* slab_manager);
void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback);
iterator end() {
@@ -100,27 +101,28 @@ public:
return m_memory_block_tree.cend();
}
VAddr FindFreeArea(VAddr region_start, size_t region_num_pages, size_t num_pages,
size_t alignment, size_t offset, size_t guard_pages) const;
KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
size_t num_pages, size_t alignment, size_t offset,
size_t guard_pages) const;
void Update(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address, size_t num_pages,
KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr,
void Update(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr,
KMemoryBlockDisableMergeAttribute set_disable_attr,
KMemoryBlockDisableMergeAttribute clear_disable_attr);
void UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address, size_t num_pages,
MemoryBlockLockFunction lock_func, KMemoryPermission perm);
void UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm);
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm,
KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm,
KMemoryAttribute attr);
iterator FindIterator(VAddr address) const {
iterator FindIterator(KProcessAddress address) const {
return m_memory_block_tree.find(KMemoryBlock(
address, 1, KMemoryState::Free, KMemoryPermission::None, KMemoryAttribute::None));
}
const KMemoryBlock* FindBlock(VAddr address) const {
const KMemoryBlock* FindBlock(KProcessAddress address) const {
if (const_iterator it = this->FindIterator(address); it != m_memory_block_tree.end()) {
return std::addressof(*it);
}
@@ -132,12 +134,12 @@ public:
bool CheckState() const;
private:
void CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
void CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages);
MemoryBlockTree m_memory_block_tree;
VAddr m_start_address{};
VAddr m_end_address{};
KProcessAddress m_start_address{};
KProcessAddress m_end_address{};
};
class KScopedMemoryBlockManagerAuditor {

View File

@@ -18,11 +18,11 @@ KMemoryRegion* AllocateRegion(KMemoryRegionAllocator& memory_region_allocator, A
} // namespace
KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_)
: memory_region_allocator{memory_region_allocator_} {}
KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator)
: m_memory_region_allocator{memory_region_allocator} {}
void KMemoryRegionTree::InsertDirectly(u64 address, u64 last_address, u32 attr, u32 type_id) {
this->insert(*AllocateRegion(memory_region_allocator, address, last_address, attr, type_id));
this->insert(*AllocateRegion(m_memory_region_allocator, address, last_address, attr, type_id));
}
bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) {
@@ -69,7 +69,7 @@ bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_at
const u64 new_pair = (old_pair != std::numeric_limits<u64>::max())
? old_pair + (address - old_address)
: old_pair;
this->insert(*AllocateRegion(memory_region_allocator, address, inserted_region_last,
this->insert(*AllocateRegion(m_memory_region_allocator, address, inserted_region_last,
new_pair, new_attr, type_id));
}
@@ -78,14 +78,15 @@ bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_at
const u64 after_pair = (old_pair != std::numeric_limits<u64>::max())
? old_pair + (inserted_region_end - old_address)
: old_pair;
this->insert(*AllocateRegion(memory_region_allocator, inserted_region_end, old_last,
this->insert(*AllocateRegion(m_memory_region_allocator, inserted_region_end, old_last,
after_pair, old_attr, old_type));
}
return true;
}
VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id) {
KVirtualAddress KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment,
u32 type_id) {
// We want to find the total extents of the type id.
const auto extents = this->GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
@@ -126,14 +127,17 @@ VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u
}
KMemoryLayout::KMemoryLayout()
: virtual_tree{memory_region_allocator}, physical_tree{memory_region_allocator},
virtual_linear_tree{memory_region_allocator}, physical_linear_tree{memory_region_allocator} {}
: m_virtual_tree{m_memory_region_allocator}, m_physical_tree{m_memory_region_allocator},
m_virtual_linear_tree{m_memory_region_allocator}, m_physical_linear_tree{
m_memory_region_allocator} {}
void KMemoryLayout::InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
VAddr linear_virtual_start) {
void KMemoryLayout::InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start,
KVirtualAddress linear_virtual_start) {
// Set static differences.
linear_phys_to_virt_diff = linear_virtual_start - aligned_linear_phys_start;
linear_virt_to_phys_diff = aligned_linear_phys_start - linear_virtual_start;
m_linear_phys_to_virt_diff =
GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
m_linear_virt_to_phys_diff =
GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
// Initialize linear trees.
for (auto& region : GetPhysicalMemoryRegionTree()) {

View File

@@ -10,6 +10,7 @@
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_region.h"
#include "core/hle/kernel/k_memory_region_type.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel {
@@ -69,10 +70,11 @@ constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelIniti
//! NB: Use KThread::GetAddressKeyIsKernel().
//! See explanation for deviation of GetAddressKey.
bool IsKernelAddressKey(VAddr key) = delete;
bool IsKernelAddressKey(KProcessAddress key) = delete;
constexpr bool IsKernelAddress(VAddr address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
constexpr bool IsKernelAddress(KProcessAddress address) {
return KernelVirtualAddressSpaceBase <= GetInteger(address) &&
address < KernelVirtualAddressSpaceEnd;
}
class KMemoryLayout final {
@@ -80,62 +82,62 @@ public:
KMemoryLayout();
KMemoryRegionTree& GetVirtualMemoryRegionTree() {
return virtual_tree;
return m_virtual_tree;
}
const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
return virtual_tree;
return m_virtual_tree;
}
KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
return physical_tree;
return m_physical_tree;
}
const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
return physical_tree;
return m_physical_tree;
}
KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
return virtual_linear_tree;
return m_virtual_linear_tree;
}
const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
return virtual_linear_tree;
return m_virtual_linear_tree;
}
KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
return physical_linear_tree;
return m_physical_linear_tree;
}
const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
return physical_linear_tree;
return m_physical_linear_tree;
}
VAddr GetLinearVirtualAddress(PAddr address) const {
return address + linear_phys_to_virt_diff;
KVirtualAddress GetLinearVirtualAddress(KPhysicalAddress address) const {
return GetInteger(address) + m_linear_phys_to_virt_diff;
}
PAddr GetLinearPhysicalAddress(VAddr address) const {
return address + linear_virt_to_phys_diff;
KPhysicalAddress GetLinearPhysicalAddress(KVirtualAddress address) const {
return GetInteger(address) + m_linear_virt_to_phys_diff;
}
const KMemoryRegion* FindVirtual(VAddr address) const {
const KMemoryRegion* FindVirtual(KVirtualAddress address) const {
return Find(address, GetVirtualMemoryRegionTree());
}
const KMemoryRegion* FindPhysical(PAddr address) const {
const KMemoryRegion* FindPhysical(KPhysicalAddress address) const {
return Find(address, GetPhysicalMemoryRegionTree());
}
const KMemoryRegion* FindVirtualLinear(VAddr address) const {
const KMemoryRegion* FindVirtualLinear(KVirtualAddress address) const {
return Find(address, GetVirtualLinearMemoryRegionTree());
}
const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
const KMemoryRegion* FindPhysicalLinear(KPhysicalAddress address) const {
return Find(address, GetPhysicalLinearMemoryRegionTree());
}
VAddr GetMainStackTopAddress(s32 core_id) const {
KVirtualAddress GetMainStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
}
VAddr GetIdleStackTopAddress(s32 core_id) const {
KVirtualAddress GetIdleStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
}
VAddr GetExceptionStackTopAddress(s32 core_id) const {
KVirtualAddress GetExceptionStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
}
VAddr GetSlabRegionAddress() const {
KVirtualAddress GetSlabRegionAddress() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
.GetAddress();
}
@@ -143,10 +145,10 @@ public:
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
}
PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
KPhysicalAddress GetDevicePhysicalAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetAddress();
}
VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
KVirtualAddress GetDeviceVirtualAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetPairAddress();
}
@@ -175,11 +177,11 @@ public:
KMemoryRegionType_VirtualDramKernelSecureAppletMemory));
}
const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
const KMemoryRegion& GetVirtualLinearRegion(KVirtualAddress address) const {
return Dereference(FindVirtualLinear(address));
}
const KMemoryRegion& GetPhysicalLinearRegion(PAddr address) const {
const KMemoryRegion& GetPhysicalLinearRegion(KPhysicalAddress address) const {
return Dereference(FindPhysicalLinear(address));
}
@@ -193,29 +195,32 @@ public:
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
}
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, KPhysicalAddress address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
bool IsHeapVirtualAddress(const KMemoryRegion*& region, KVirtualAddress address) const {
return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, KPhysicalAddress address,
size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
bool IsHeapVirtualAddress(const KMemoryRegion*& region, KVirtualAddress address,
size_t size) const {
return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region,
KPhysicalAddress address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
}
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, KPhysicalAddress address,
size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
@@ -234,8 +239,8 @@ public:
return std::make_pair(total_size, kernel_size);
}
void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
VAddr linear_virtual_start);
void InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start,
KVirtualAddress linear_virtual_start);
static size_t GetResourceRegionSizeForInit(bool use_extra_resource);
auto GetKernelRegionExtents() const {
@@ -261,8 +266,8 @@ public:
auto GetLinearRegionVirtualExtents() const {
const auto physical = GetLinearRegionPhysicalExtents();
return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
GetLinearVirtualAddress(physical.GetLastAddress()), 0,
return KMemoryRegion(GetInteger(GetLinearVirtualAddress(physical.GetAddress())),
GetInteger(GetLinearVirtualAddress(physical.GetLastAddress())), 0,
KMemoryRegionType_None);
}
@@ -334,12 +339,12 @@ private:
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
const KMemoryRegionTree& tree, KMemoryRegionType type) {
// Check if the cached region already contains the address.
if (region != nullptr && region->Contains(address)) {
if (region != nullptr && region->Contains(GetInteger(address))) {
return true;
}
// Find the containing region, and update the cache.
if (const KMemoryRegion* found = tree.Find(address);
if (const KMemoryRegion* found = tree.Find(GetInteger(address));
found != nullptr && found->IsDerivedFrom(type)) {
region = found;
return true;
@@ -352,11 +357,12 @@ private:
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
const KMemoryRegionTree& tree, KMemoryRegionType type) {
// Get the end of the checked region.
const u64 last_address = address + size - 1;
const u64 last_address = GetInteger(address) + size - 1;
// Walk the tree to verify the region is correct.
const KMemoryRegion* cur =
(region != nullptr && region->Contains(address)) ? region : tree.Find(address);
const KMemoryRegion* cur = (region != nullptr && region->Contains(GetInteger(address)))
? region
: tree.Find(GetInteger(address));
while (cur != nullptr && cur->IsDerivedFrom(type)) {
if (last_address <= cur->GetLastAddress()) {
region = cur;
@@ -370,7 +376,7 @@ private:
template <typename AddressType>
static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
return tree.Find(address);
return tree.Find(GetInteger(address));
}
static KMemoryRegion& Dereference(KMemoryRegion* region) {
@@ -383,7 +389,7 @@ private:
return *region;
}
VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
KVirtualAddress GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
const auto& region = Dereference(
GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
ASSERT(region.GetEndAddress() != 0);
@@ -391,13 +397,13 @@ private:
}
private:
u64 linear_phys_to_virt_diff{};
u64 linear_virt_to_phys_diff{};
KMemoryRegionAllocator memory_region_allocator;
KMemoryRegionTree virtual_tree;
KMemoryRegionTree physical_tree;
KMemoryRegionTree virtual_linear_tree;
KMemoryRegionTree physical_linear_tree;
u64 m_linear_phys_to_virt_diff{};
u64 m_linear_virt_to_phys_diff{};
KMemoryRegionAllocator m_memory_region_allocator;
KMemoryRegionTree m_virtual_tree;
KMemoryRegionTree m_physical_tree;
KMemoryRegionTree m_virtual_linear_tree;
KMemoryRegionTree m_physical_linear_tree;
};
namespace Init {

View File

@@ -5,7 +5,6 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/device_memory.h"
@@ -44,10 +43,10 @@ KMemoryManager::KMemoryManager(Core::System& system)
KLightLock{system.Kernel()},
} {}
void KMemoryManager::Initialize(VAddr management_region, size_t management_region_size) {
void KMemoryManager::Initialize(KVirtualAddress management_region, size_t management_region_size) {
// Clear the management region to zero.
const VAddr management_region_end = management_region + management_region_size;
const KVirtualAddress management_region_end = management_region + management_region_size;
// std::memset(GetVoidPointer(management_region), 0, management_region_size);
// Reset our manager count.
@@ -56,7 +55,7 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
// Traverse the virtual memory layout tree, initializing each manager as appropriate.
while (m_num_managers != MaxManagerCount) {
// Locate the region that should initialize the current manager.
PAddr region_address = 0;
KPhysicalAddress region_address = 0;
size_t region_size = 0;
Pool region_pool = Pool::Count;
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
@@ -70,8 +69,8 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
continue;
}
const PAddr cur_start = it.GetAddress();
const PAddr cur_end = it.GetEndAddress();
const KPhysicalAddress cur_start = it.GetAddress();
const KPhysicalAddress cur_end = it.GetEndAddress();
// Validate the region.
ASSERT(cur_end != 0);
@@ -119,17 +118,17 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
// Free each region to its corresponding heap.
size_t reserved_sizes[MaxManagerCount] = {};
const PAddr ini_start = GetInitialProcessBinaryPhysicalAddress();
const PAddr ini_end = ini_start + InitialProcessBinarySizeMax;
const PAddr ini_last = ini_end - 1;
const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress();
const KPhysicalAddress ini_end = ini_start + InitialProcessBinarySizeMax;
const KPhysicalAddress ini_last = ini_end - 1;
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
// Get the manager for the region.
auto& manager = m_managers[it.GetAttributes()];
const PAddr cur_start = it.GetAddress();
const PAddr cur_last = it.GetLastAddress();
const PAddr cur_end = it.GetEndAddress();
const KPhysicalAddress cur_start = it.GetAddress();
const KPhysicalAddress cur_last = it.GetLastAddress();
const KPhysicalAddress cur_end = it.GetEndAddress();
if (cur_start <= ini_start && ini_last <= cur_last) {
// Free memory before the ini to the heap.
@@ -175,7 +174,8 @@ void KMemoryManager::FinalizeOptimizedMemory(u64 process_id, Pool pool) {
UNREACHABLE();
}
PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option) {
KPhysicalAddress KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages,
u32 option) {
// Early return if we're allocating no pages.
if (num_pages == 0) {
return 0;
@@ -190,7 +190,7 @@ PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_p
// Loop, trying to iterate from each block.
Impl* chosen_manager = nullptr;
PAddr allocated_block = 0;
KPhysicalAddress allocated_block = 0;
for (chosen_manager = this->GetFirstManager(pool, dir); chosen_manager != nullptr;
chosen_manager = this->GetNextManager(chosen_manager, dir)) {
allocated_block = chosen_manager->AllocateAligned(heap_index, num_pages, align_pages);
@@ -239,7 +239,7 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,
cur_manager = this->GetNextManager(cur_manager, dir)) {
while (num_pages >= pages_per_alloc) {
// Allocate a block.
PAddr allocated_block = cur_manager->AllocateBlock(index, random);
KPhysicalAddress allocated_block = cur_manager->AllocateBlock(index, random);
if (allocated_block == 0) {
break;
}
@@ -286,7 +286,7 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op
// Open the first reference to the pages.
for (const auto& block : *out) {
PAddr cur_address = block.GetAddress();
KPhysicalAddress cur_address = block.GetAddress();
size_t remaining_pages = block.GetNumPages();
while (remaining_pages > 0) {
// Get the manager for the current address.
@@ -337,7 +337,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
// Iterate over the allocated blocks.
for (const auto& block : *out) {
// Get the block extents.
const PAddr block_address = block.GetAddress();
const KPhysicalAddress block_address = block.GetAddress();
const size_t block_pages = block.GetNumPages();
// If it has no pages, we don't need to do anything.
@@ -348,7 +348,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
// Fill all the pages that we need to fill.
bool any_new = false;
{
PAddr cur_address = block_address;
KPhysicalAddress cur_address = block_address;
size_t remaining_pages = block_pages;
while (remaining_pages > 0) {
// Get the manager for the current address.
@@ -369,7 +369,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
// If there are new pages, update tracking for the allocation.
if (any_new) {
// Update tracking for the allocation.
PAddr cur_address = block_address;
KPhysicalAddress cur_address = block_address;
size_t remaining_pages = block_pages;
while (remaining_pages > 0) {
// Get the manager for the current address.
@@ -400,8 +400,9 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
R_SUCCEED();
}
size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr management,
VAddr management_end, Pool p) {
size_t KMemoryManager::Impl::Initialize(KPhysicalAddress address, size_t size,
KVirtualAddress management, KVirtualAddress management_end,
Pool p) {
// Calculate management sizes.
const size_t ref_count_size = (size / PageSize) * sizeof(u16);
const size_t optimize_map_size = CalculateOptimizedProcessOverheadSize(size);
@@ -417,7 +418,7 @@ size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr manage
m_management_region = management;
m_page_reference_counts.resize(
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize() / PageSize);
ASSERT(Common::IsAligned(m_management_region, PageSize));
ASSERT(Common::IsAligned(GetInteger(m_management_region), PageSize));
// Initialize the manager's KPageHeap.
m_heap.Initialize(address, size, management + manager_size, page_heap_size);
@@ -425,15 +426,15 @@ size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr manage
return total_management_size;
}
void KMemoryManager::Impl::TrackUnoptimizedAllocation(PAddr block, size_t num_pages) {
void KMemoryManager::Impl::TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages) {
UNREACHABLE();
}
void KMemoryManager::Impl::TrackOptimizedAllocation(PAddr block, size_t num_pages) {
void KMemoryManager::Impl::TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages) {
UNREACHABLE();
}
bool KMemoryManager::Impl::ProcessOptimizedAllocation(PAddr block, size_t num_pages,
bool KMemoryManager::Impl::ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages,
u8 fill_pattern) {
UNREACHABLE();
}

View File

@@ -7,10 +7,10 @@
#include <tuple>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_page_heap.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/result.h"
namespace Core {
@@ -50,21 +50,21 @@ public:
explicit KMemoryManager(Core::System& system);
void Initialize(VAddr management_region, size_t management_region_size);
void Initialize(KVirtualAddress management_region, size_t management_region_size);
Result InitializeOptimizedMemory(u64 process_id, Pool pool);
void FinalizeOptimizedMemory(u64 process_id, Pool pool);
PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
Result AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option);
Result AllocateForProcess(KPageGroup* out, size_t num_pages, u32 option, u64 process_id,
u8 fill_pattern);
Pool GetPool(PAddr address) const {
Pool GetPool(KPhysicalAddress address) const {
return this->GetManager(address).GetPool();
}
void Open(PAddr address, size_t num_pages) {
void Open(KPhysicalAddress address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
@@ -80,7 +80,7 @@ public:
}
}
void OpenFirst(PAddr address, size_t num_pages) {
void OpenFirst(KPhysicalAddress address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
@@ -96,7 +96,7 @@ public:
}
}
void Close(PAddr address, size_t num_pages) {
void Close(KPhysicalAddress address, size_t num_pages) {
// Repeatedly close references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
@@ -199,16 +199,16 @@ private:
public:
Impl() = default;
size_t Initialize(PAddr address, size_t size, VAddr management, VAddr management_end,
Pool p);
size_t Initialize(KPhysicalAddress address, size_t size, KVirtualAddress management,
KVirtualAddress management_end, Pool p);
PAddr AllocateBlock(s32 index, bool random) {
KPhysicalAddress AllocateBlock(s32 index, bool random) {
return m_heap.AllocateBlock(index, random);
}
PAddr AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
KPhysicalAddress AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
return m_heap.AllocateAligned(index, num_pages, align_pages);
}
void Free(PAddr addr, size_t num_pages) {
void Free(KPhysicalAddress addr, size_t num_pages) {
m_heap.Free(addr, num_pages);
}
@@ -220,10 +220,10 @@ private:
UNIMPLEMENTED();
}
void TrackUnoptimizedAllocation(PAddr block, size_t num_pages);
void TrackOptimizedAllocation(PAddr block, size_t num_pages);
void TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages);
void TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages);
bool ProcessOptimizedAllocation(PAddr block, size_t num_pages, u8 fill_pattern);
bool ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages, u8 fill_pattern);
constexpr Pool GetPool() const {
return m_pool;
@@ -231,7 +231,7 @@ private:
constexpr size_t GetSize() const {
return m_heap.GetSize();
}
constexpr PAddr GetEndAddress() const {
constexpr KPhysicalAddress GetEndAddress() const {
return m_heap.GetEndAddress();
}
@@ -243,10 +243,10 @@ private:
UNIMPLEMENTED();
}
constexpr size_t GetPageOffset(PAddr address) const {
constexpr size_t GetPageOffset(KPhysicalAddress address) const {
return m_heap.GetPageOffset(address);
}
constexpr size_t GetPageOffsetToEnd(PAddr address) const {
constexpr size_t GetPageOffsetToEnd(KPhysicalAddress address) const {
return m_heap.GetPageOffsetToEnd(address);
}
@@ -263,7 +263,7 @@ private:
return m_prev;
}
void OpenFirst(PAddr address, size_t num_pages) {
void OpenFirst(KPhysicalAddress address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
@@ -274,7 +274,7 @@ private:
}
}
void Open(PAddr address, size_t num_pages) {
void Open(KPhysicalAddress address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
@@ -285,7 +285,7 @@ private:
}
}
void Close(PAddr address, size_t num_pages) {
void Close(KPhysicalAddress address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
@@ -323,18 +323,18 @@ private:
KPageHeap m_heap;
std::vector<RefCount> m_page_reference_counts;
VAddr m_management_region{};
KVirtualAddress m_management_region{};
Pool m_pool{};
Impl* m_next{};
Impl* m_prev{};
};
private:
Impl& GetManager(PAddr address) {
Impl& GetManager(KPhysicalAddress address) {
return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}
const Impl& GetManager(PAddr address) const {
const Impl& GetManager(KPhysicalAddress address) const {
return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}

View File

@@ -5,9 +5,9 @@
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
#include "core/hle/kernel/k_memory_region_type.h"
#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
@@ -21,15 +21,15 @@ public:
YUZU_NON_MOVEABLE(KMemoryRegion);
constexpr KMemoryRegion() = default;
constexpr KMemoryRegion(u64 address_, u64 last_address_)
: address{address_}, last_address{last_address_} {}
constexpr KMemoryRegion(u64 address_, u64 last_address_, u64 pair_address_, u32 attributes_,
u32 type_id_)
: address(address_), last_address(last_address_), pair_address(pair_address_),
attributes(attributes_), type_id(type_id_) {}
constexpr KMemoryRegion(u64 address_, u64 last_address_, u32 attributes_, u32 type_id_)
: KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
type_id_) {}
constexpr KMemoryRegion(u64 address, u64 last_address)
: m_address{address}, m_last_address{last_address} {}
constexpr KMemoryRegion(u64 address, u64 last_address, u64 pair_address, u32 attributes,
u32 type_id)
: m_address(address), m_last_address(last_address), m_pair_address(pair_address),
m_attributes(attributes), m_type_id(type_id) {}
constexpr KMemoryRegion(u64 address, u64 last_address, u32 attributes, u32 type_id)
: KMemoryRegion(address, last_address, std::numeric_limits<u64>::max(), attributes,
type_id) {}
~KMemoryRegion() = default;
@@ -44,15 +44,15 @@ public:
}
constexpr u64 GetAddress() const {
return address;
return m_address;
}
constexpr u64 GetPairAddress() const {
return pair_address;
return m_pair_address;
}
constexpr u64 GetLastAddress() const {
return last_address;
return m_last_address;
}
constexpr u64 GetEndAddress() const {
@@ -64,16 +64,16 @@ public:
}
constexpr u32 GetAttributes() const {
return attributes;
return m_attributes;
}
constexpr u32 GetType() const {
return type_id;
return m_type_id;
}
constexpr void SetType(u32 type) {
ASSERT(this->CanDerive(type));
type_id = type;
m_type_id = type;
}
constexpr bool Contains(u64 addr) const {
@@ -94,27 +94,27 @@ public:
}
constexpr void SetPairAddress(u64 a) {
pair_address = a;
m_pair_address = a;
}
constexpr void SetTypeAttribute(u32 attr) {
type_id |= attr;
m_type_id |= attr;
}
private:
constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
address = a;
pair_address = p;
last_address = la;
attributes = r;
type_id = t;
m_address = a;
m_pair_address = p;
m_last_address = la;
m_attributes = r;
m_type_id = t;
}
u64 address{};
u64 last_address{};
u64 pair_address{};
u32 attributes{};
u32 type_id{};
u64 m_address{};
u64 m_last_address{};
u64 m_pair_address{};
u32 m_attributes{};
u32 m_type_id{};
};
class KMemoryRegionTree final {
@@ -243,10 +243,10 @@ public:
void InsertDirectly(u64 address, u64 last_address, u32 attr = 0, u32 type_id = 0);
bool Insert(u64 address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
VAddr GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
KVirtualAddress GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
VAddr GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
size_t guard_size) {
KVirtualAddress GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
size_t guard_size) {
return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
}
@@ -322,7 +322,7 @@ public:
private:
TreeType m_tree{};
KMemoryRegionAllocator& memory_region_allocator;
KMemoryRegionAllocator& m_memory_region_allocator;
};
class KMemoryRegionAllocator final {
@@ -338,18 +338,18 @@ public:
template <typename... Args>
KMemoryRegion* Allocate(Args&&... args) {
// Ensure we stay within the bounds of our heap.
ASSERT(this->num_regions < MaxMemoryRegions);
ASSERT(m_num_regions < MaxMemoryRegions);
// Create the new region.
KMemoryRegion* region = std::addressof(this->region_heap[this->num_regions++]);
new (region) KMemoryRegion(std::forward<Args>(args)...);
KMemoryRegion* region = std::addressof(m_region_heap[m_num_regions++]);
std::construct_at(region, std::forward<Args>(args)...);
return region;
}
private:
std::array<KMemoryRegion, MaxMemoryRegions> region_heap{};
size_t num_regions{};
std::array<KMemoryRegion, MaxMemoryRegions> m_region_heap{};
size_t m_num_regions{};
};
} // namespace Kernel

View File

@@ -41,7 +41,7 @@ public:
// Check that the object is closed.
R_UNLESS(derived->IsServerClosed(), ResultInvalidState);
return Delete(kernel, obj.GetPointerUnsafe(), name);
R_RETURN(Delete(kernel, obj.GetPointerUnsafe(), name));
}
template <typename Derived>

View File

@@ -10,8 +10,8 @@
namespace Kernel {
KPageBuffer* KPageBuffer::FromPhysicalAddress(Core::System& system, PAddr phys_addr) {
ASSERT(Common::IsAligned(phys_addr, PageSize));
KPageBuffer* KPageBuffer::FromPhysicalAddress(Core::System& system, KPhysicalAddress phys_addr) {
ASSERT(Common::IsAligned(GetInteger(phys_addr), PageSize));
return system.DeviceMemory().GetPointer<KPageBuffer>(phys_addr);
}

View File

@@ -26,10 +26,10 @@ public:
explicit KPageBuffer(KernelCore&) {}
KPageBuffer() = default;
static KPageBuffer* FromPhysicalAddress(Core::System& system, PAddr phys_addr);
static KPageBuffer* FromPhysicalAddress(Core::System& system, KPhysicalAddress phys_addr);
private:
[[maybe_unused]] alignas(PageSize) std::array<u8, PageSize> m_buffer{};
alignas(PageSize) std::array<u8, PageSize> m_buffer{};
};
static_assert(sizeof(KPageBuffer) == KPageBufferSlabHeap::BufferSize);

View File

@@ -22,7 +22,7 @@ public:
constexpr explicit KBlockInfo() : m_next(nullptr) {}
constexpr void Initialize(KPhysicalAddress addr, size_t np) {
ASSERT(Common::IsAligned(addr, PageSize));
ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
ASSERT(static_cast<u32>(np) == np);
m_page_index = static_cast<u32>(addr / PageSize);

View File

@@ -6,14 +6,14 @@
namespace Kernel {
void KPageHeap::Initialize(PAddr address, size_t size, VAddr management_address,
size_t management_size, const size_t* block_shifts,
size_t num_block_shifts) {
void KPageHeap::Initialize(KPhysicalAddress address, size_t size,
KVirtualAddress management_address, size_t management_size,
const size_t* block_shifts, size_t num_block_shifts) {
// Check our assumptions.
ASSERT(Common::IsAligned(address, PageSize));
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT(Common::IsAligned(size, PageSize));
ASSERT(0 < num_block_shifts && num_block_shifts <= NumMemoryBlockPageShifts);
const VAddr management_end = management_address + management_size;
const KVirtualAddress management_end = management_address + management_size;
// Set our members.
m_heap_address = address;
@@ -31,7 +31,7 @@ void KPageHeap::Initialize(PAddr address, size_t size, VAddr management_address,
}
// Ensure we didn't overextend our bounds.
ASSERT(VAddr(cur_bitmap_storage) <= management_end);
ASSERT(KVirtualAddress(cur_bitmap_storage) <= management_end);
}
size_t KPageHeap::GetNumFreePages() const {
@@ -44,11 +44,11 @@ size_t KPageHeap::GetNumFreePages() const {
return num_free;
}
PAddr KPageHeap::AllocateByLinearSearch(s32 index) {
KPhysicalAddress KPageHeap::AllocateByLinearSearch(s32 index) {
const size_t needed_size = m_blocks[index].GetSize();
for (s32 i = index; i < static_cast<s32>(m_num_blocks); i++) {
if (const PAddr addr = m_blocks[i].PopBlock(false); addr != 0) {
if (const KPhysicalAddress addr = m_blocks[i].PopBlock(false); addr != 0) {
if (const size_t allocated_size = m_blocks[i].GetSize(); allocated_size > needed_size) {
this->Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
}
@@ -59,7 +59,7 @@ PAddr KPageHeap::AllocateByLinearSearch(s32 index) {
return 0;
}
PAddr KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_pages) {
KPhysicalAddress KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_pages) {
// Get the size and required alignment.
const size_t needed_size = num_pages * PageSize;
const size_t align_size = align_pages * PageSize;
@@ -110,7 +110,7 @@ PAddr KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_page
}
// Pop a block from the index we selected.
if (PAddr addr = m_blocks[index].PopBlock(true); addr != 0) {
if (KPhysicalAddress addr = m_blocks[index].PopBlock(true); addr != 0) {
// Determine how much size we have left over.
if (const size_t leftover_size = m_blocks[index].GetSize() - needed_size;
leftover_size > 0) {
@@ -141,13 +141,13 @@ PAddr KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_page
return 0;
}
void KPageHeap::FreeBlock(PAddr block, s32 index) {
void KPageHeap::FreeBlock(KPhysicalAddress block, s32 index) {
do {
block = m_blocks[index++].PushBlock(block);
} while (block != 0);
}
void KPageHeap::Free(PAddr addr, size_t num_pages) {
void KPageHeap::Free(KPhysicalAddress addr, size_t num_pages) {
// Freeing no pages is a no-op.
if (num_pages == 0) {
return;
@@ -155,16 +155,16 @@ void KPageHeap::Free(PAddr addr, size_t num_pages) {
// Find the largest block size that we can free, and free as many as possible.
s32 big_index = static_cast<s32>(m_num_blocks) - 1;
const PAddr start = addr;
const PAddr end = addr + num_pages * PageSize;
PAddr before_start = start;
PAddr before_end = start;
PAddr after_start = end;
PAddr after_end = end;
const KPhysicalAddress start = addr;
const KPhysicalAddress end = addr + num_pages * PageSize;
KPhysicalAddress before_start = start;
KPhysicalAddress before_end = start;
KPhysicalAddress after_start = end;
KPhysicalAddress after_end = end;
while (big_index >= 0) {
const size_t block_size = m_blocks[big_index].GetSize();
const PAddr big_start = Common::AlignUp(start, block_size);
const PAddr big_end = Common::AlignDown(end, block_size);
const KPhysicalAddress big_start = Common::AlignUp(GetInteger(start), block_size);
const KPhysicalAddress big_end = Common::AlignDown(GetInteger(end), block_size);
if (big_start < big_end) {
// Free as many big blocks as we can.
for (auto block = big_start; block < big_end; block += block_size) {

View File

@@ -8,8 +8,8 @@
#include "common/alignment.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_page_bitmap.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel {
@@ -18,24 +18,24 @@ class KPageHeap {
public:
KPageHeap() = default;
constexpr PAddr GetAddress() const {
constexpr KPhysicalAddress GetAddress() const {
return m_heap_address;
}
constexpr size_t GetSize() const {
return m_heap_size;
}
constexpr PAddr GetEndAddress() const {
constexpr KPhysicalAddress GetEndAddress() const {
return this->GetAddress() + this->GetSize();
}
constexpr size_t GetPageOffset(PAddr block) const {
constexpr size_t GetPageOffset(KPhysicalAddress block) const {
return (block - this->GetAddress()) / PageSize;
}
constexpr size_t GetPageOffsetToEnd(PAddr block) const {
constexpr size_t GetPageOffsetToEnd(KPhysicalAddress block) const {
return (this->GetEndAddress() - block) / PageSize;
}
void Initialize(PAddr heap_address, size_t heap_size, VAddr management_address,
size_t management_size) {
void Initialize(KPhysicalAddress heap_address, size_t heap_size,
KVirtualAddress management_address, size_t management_size) {
return this->Initialize(heap_address, heap_size, management_address, management_size,
MemoryBlockPageShifts.data(), NumMemoryBlockPageShifts);
}
@@ -53,7 +53,7 @@ public:
m_initial_used_size = m_heap_size - free_size - reserved_size;
}
PAddr AllocateBlock(s32 index, bool random) {
KPhysicalAddress AllocateBlock(s32 index, bool random) {
if (random) {
const size_t block_pages = m_blocks[index].GetNumPages();
return this->AllocateByRandom(index, block_pages, block_pages);
@@ -62,12 +62,12 @@ public:
}
}
PAddr AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
KPhysicalAddress AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
// TODO: linear search support?
return this->AllocateByRandom(index, num_pages, align_pages);
}
void Free(PAddr addr, size_t num_pages);
void Free(KPhysicalAddress addr, size_t num_pages);
static size_t CalculateManagementOverheadSize(size_t region_size) {
return CalculateManagementOverheadSize(region_size, MemoryBlockPageShifts.data(),
@@ -125,24 +125,25 @@ private:
return this->GetNumFreeBlocks() * this->GetNumPages();
}
u64* Initialize(PAddr addr, size_t size, size_t bs, size_t nbs, u64* bit_storage) {
u64* Initialize(KPhysicalAddress addr, size_t size, size_t bs, size_t nbs,
u64* bit_storage) {
// Set shifts.
m_block_shift = bs;
m_next_block_shift = nbs;
// Align up the address.
PAddr end = addr + size;
KPhysicalAddress end = addr + size;
const size_t align = (m_next_block_shift != 0) ? (u64(1) << m_next_block_shift)
: (u64(1) << m_block_shift);
addr = Common::AlignDown(addr, align);
end = Common::AlignUp(end, align);
addr = Common::AlignDown(GetInteger(addr), align);
end = Common::AlignUp(GetInteger(end), align);
m_heap_address = addr;
m_end_offset = (end - addr) / (u64(1) << m_block_shift);
return m_bitmap.Initialize(bit_storage, m_end_offset);
}
PAddr PushBlock(PAddr address) {
KPhysicalAddress PushBlock(KPhysicalAddress address) {
// Set the bit for the free block.
size_t offset = (address - m_heap_address) >> this->GetShift();
m_bitmap.SetBit(offset);
@@ -161,7 +162,7 @@ private:
return {};
}
PAddr PopBlock(bool random) {
KPhysicalAddress PopBlock(bool random) {
// Find a free block.
s64 soffset = m_bitmap.FindFreeBlock(random);
if (soffset < 0) {
@@ -187,18 +188,19 @@ private:
private:
KPageBitmap m_bitmap;
PAddr m_heap_address{};
KPhysicalAddress m_heap_address{};
uintptr_t m_end_offset{};
size_t m_block_shift{};
size_t m_next_block_shift{};
};
private:
void Initialize(PAddr heap_address, size_t heap_size, VAddr management_address,
size_t management_size, const size_t* block_shifts, size_t num_block_shifts);
void Initialize(KPhysicalAddress heap_address, size_t heap_size,
KVirtualAddress management_address, size_t management_size,
const size_t* block_shifts, size_t num_block_shifts);
size_t GetNumFreePages() const;
void FreeBlock(PAddr block, s32 index);
void FreeBlock(KPhysicalAddress block, s32 index);
static constexpr size_t NumMemoryBlockPageShifts{7};
static constexpr std::array<size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
@@ -206,14 +208,14 @@ private:
};
private:
PAddr AllocateByLinearSearch(s32 index);
PAddr AllocateByRandom(s32 index, size_t num_pages, size_t align_pages);
KPhysicalAddress AllocateByLinearSearch(s32 index);
KPhysicalAddress AllocateByRandom(s32 index, size_t num_pages, size_t align_pages);
static size_t CalculateManagementOverheadSize(size_t region_size, const size_t* block_shifts,
size_t num_block_shifts);
private:
PAddr m_heap_address{};
KPhysicalAddress m_heap_address{};
size_t m_heap_size{};
size_t m_initial_used_size{};
size_t m_num_blocks{};

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,6 @@
#include <memory>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/page_table.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
@@ -15,6 +14,7 @@
#include "core/hle/kernel/k_memory_block_manager.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/result.h"
#include "core/memory.h"
@@ -65,45 +65,47 @@ public:
Result InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
bool enable_das_merge, bool from_back, KMemoryManager::Pool pool,
VAddr code_addr, size_t code_size, KSystemResource* system_resource,
KResourceLimit* resource_limit);
KProcessAddress code_addr, size_t code_size,
KSystemResource* system_resource, KResourceLimit* resource_limit);
void Finalize();
Result MapProcessCode(VAddr addr, size_t pages_count, KMemoryState state,
Result MapProcessCode(KProcessAddress addr, size_t pages_count, KMemoryState state,
KMemoryPermission perm);
Result MapCodeMemory(VAddr dst_address, VAddr src_address, size_t size);
Result UnmapCodeMemory(VAddr dst_address, VAddr src_address, size_t size,
Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size,
ICacheInvalidationStrategy icache_invalidation_strategy);
Result UnmapProcessMemory(VAddr dst_addr, size_t size, KPageTable& src_page_table,
VAddr src_addr);
Result MapPhysicalMemory(VAddr addr, size_t size);
Result UnmapPhysicalMemory(VAddr addr, size_t size);
Result MapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
Result UnmapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
Result SetProcessMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm);
KMemoryInfo QueryInfo(VAddr addr);
Result SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission perm);
Result SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr);
Result UnmapProcessMemory(KProcessAddress dst_addr, size_t size, KPageTable& src_page_table,
KProcessAddress src_addr);
Result MapPhysicalMemory(KProcessAddress addr, size_t size);
Result UnmapPhysicalMemory(KProcessAddress addr, size_t size);
Result MapMemory(KProcessAddress dst_addr, KProcessAddress src_addr, size_t size);
Result UnmapMemory(KProcessAddress dst_addr, KProcessAddress src_addr, size_t size);
Result SetProcessMemoryPermission(KProcessAddress addr, size_t size,
Svc::MemoryPermission svc_perm);
KMemoryInfo QueryInfo(KProcessAddress addr);
Result SetMemoryPermission(KProcessAddress addr, size_t size, Svc::MemoryPermission perm);
Result SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr);
Result SetMaxHeapSize(size_t size);
Result SetHeapSize(VAddr* out, size_t size);
Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
Result SetHeapSize(u64* out, size_t size);
Result LockForMapDeviceAddressSpace(bool* out_is_io, KProcessAddress address, size_t size,
KMemoryPermission perm, bool is_aligned, bool check_heap);
Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap);
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap);
Result UnlockForDeviceAddressSpace(VAddr addr, size_t size);
Result UnlockForDeviceAddressSpace(KProcessAddress addr, size_t size);
Result LockForIpcUserBuffer(PAddr* out, VAddr address, size_t size);
Result UnlockForIpcUserBuffer(VAddr address, size_t size);
Result LockForIpcUserBuffer(KPhysicalAddress* out, KProcessAddress address, size_t size);
Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size);
Result SetupForIpc(VAddr* out_dst_addr, size_t size, VAddr src_addr, KPageTable& src_page_table,
KMemoryPermission test_perm, KMemoryState dst_state, bool send);
Result CleanupForIpcServer(VAddr address, size_t size, KMemoryState dst_state);
Result CleanupForIpcClient(VAddr address, size_t size, KMemoryState dst_state);
Result SetupForIpc(KProcessAddress* out_dst_addr, size_t size, KProcessAddress src_addr,
KPageTable& src_page_table, KMemoryPermission test_perm,
KMemoryState dst_state, bool send);
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
Result LockForCodeMemory(KPageGroup* out, VAddr addr, size_t size);
Result UnlockForCodeMemory(VAddr addr, size_t size, const KPageGroup& pg);
Result MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t num_pages,
Result LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size);
Result UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg);
Result MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr);
@@ -120,7 +122,7 @@ public:
return m_block_info_manager;
}
bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
KPhysicalAddress phys_addr, KProcessAddress region_start,
@@ -173,8 +175,8 @@ protected:
m_root = n;
}
void Push(Core::Memory::Memory& memory, VAddr addr) {
this->Push(memory.GetPointer<Node>(addr));
void Push(Core::Memory::Memory& memory, KVirtualAddress addr) {
this->Push(memory.GetPointer<Node>(GetInteger(addr)));
}
Node* Peek() const {
@@ -212,27 +214,28 @@ private:
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start,
size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
bool IsRegionContiguous(VAddr addr, u64 size) const;
void AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list);
KMemoryInfo QueryInfoImpl(VAddr addr);
VAddr AllocateVirtualMemory(VAddr start, size_t region_num_pages, u64 needed_num_pages,
size_t align);
Result Operate(VAddr addr, size_t num_pages, const KPageGroup& page_group,
bool IsRegionContiguous(KProcessAddress addr, u64 size) const;
void AddRegionToPages(KProcessAddress start, size_t num_pages, KPageGroup& page_linked_list);
KMemoryInfo QueryInfoImpl(KProcessAddress addr);
KProcessAddress AllocateVirtualMemory(KProcessAddress start, size_t region_num_pages,
u64 needed_num_pages, size_t align);
Result Operate(KProcessAddress addr, size_t num_pages, const KPageGroup& page_group,
OperationType operation);
Result Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, OperationType operation,
PAddr map_addr = 0);
Result Operate(KProcessAddress addr, size_t num_pages, KMemoryPermission perm,
OperationType operation, KPhysicalAddress map_addr = 0);
void FinalizeUpdate(PageLinkedList* page_list);
VAddr GetRegionAddress(KMemoryState state) const;
KProcessAddress GetRegionAddress(KMemoryState state) const;
size_t GetRegionSize(KMemoryState state) const;
VAddr FindFreeArea(VAddr region_start, size_t region_num_pages, size_t num_pages,
size_t alignment, size_t offset, size_t guard_pages);
KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
size_t num_pages, size_t alignment, size_t offset,
size_t guard_pages);
Result CheckMemoryStateContiguous(size_t* out_blocks_needed, VAddr addr, size_t size,
Result CheckMemoryStateContiguous(size_t* out_blocks_needed, KProcessAddress addr, size_t size,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
Result CheckMemoryStateContiguous(VAddr addr, size_t size, KMemoryState state_mask,
Result CheckMemoryStateContiguous(KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr) const {
@@ -244,12 +247,12 @@ private:
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
KMemoryAttribute* out_attr, size_t* out_blocks_needed, VAddr addr,
size_t size, KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
Result CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
Result CheckMemoryState(size_t* out_blocks_needed, KProcessAddress addr, size_t size,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
@@ -258,39 +261,40 @@ private:
state_mask, state, perm_mask, perm, attr_mask, attr,
ignore_attr));
}
Result CheckMemoryState(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
Result CheckMemoryState(KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
R_RETURN(this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm,
attr_mask, attr, ignore_attr));
}
Result LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryPermission new_perm, KMemoryAttribute lock_attr);
Result UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
Result LockMemoryAndOpen(KPageGroup* out_pg, KPhysicalAddress* out_KPhysicalAddress,
KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr, KMemoryPermission new_perm,
KMemoryAttribute lock_attr);
Result UnlockMemory(KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryPermission new_perm, KMemoryAttribute lock_attr,
const KPageGroup* pg);
Result MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages);
bool IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages);
Result MakePageGroup(KPageGroup& pg, KProcessAddress addr, size_t num_pages);
bool IsValidPageGroup(const KPageGroup& pg, KProcessAddress addr, size_t num_pages);
bool IsLockedByCurrentThread() const {
return m_general_lock.IsLockedByCurrentThread();
}
bool IsHeapPhysicalAddress(const KMemoryLayout& layout, PAddr phys_addr) {
bool IsHeapPhysicalAddress(const KMemoryLayout& layout, KPhysicalAddress phys_addr) {
ASSERT(this->IsLockedByCurrentThread());
return layout.IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr);
}
bool GetPhysicalAddressLocked(PAddr* out, VAddr virt_addr) const {
bool GetPhysicalAddressLocked(KPhysicalAddress* out, KProcessAddress virt_addr) const {
ASSERT(this->IsLockedByCurrentThread());
*out = GetPhysicalAddr(virt_addr);
@@ -298,12 +302,13 @@ private:
return *out != 0;
}
Result SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed, VAddr address,
size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
Result SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_addr,
Result SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed,
KProcessAddress address, size_t size, KMemoryPermission test_perm,
KMemoryState dst_state);
Result SetupForIpcServer(KProcessAddress* out_addr, size_t size, KProcessAddress src_addr,
KMemoryPermission test_perm, KMemoryState dst_state,
KPageTable& src_page_table, bool send);
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, KProcessAddress address,
size_t size, KMemoryPermission prot_perm);
Result AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
@@ -315,61 +320,61 @@ private:
mutable KLightLock m_map_physical_memory_lock;
public:
constexpr VAddr GetAddressSpaceStart() const {
constexpr KProcessAddress GetAddressSpaceStart() const {
return m_address_space_start;
}
constexpr VAddr GetAddressSpaceEnd() const {
constexpr KProcessAddress GetAddressSpaceEnd() const {
return m_address_space_end;
}
constexpr size_t GetAddressSpaceSize() const {
return m_address_space_end - m_address_space_start;
}
constexpr VAddr GetHeapRegionStart() const {
constexpr KProcessAddress GetHeapRegionStart() const {
return m_heap_region_start;
}
constexpr VAddr GetHeapRegionEnd() const {
constexpr KProcessAddress GetHeapRegionEnd() const {
return m_heap_region_end;
}
constexpr size_t GetHeapRegionSize() const {
return m_heap_region_end - m_heap_region_start;
}
constexpr VAddr GetAliasRegionStart() const {
constexpr KProcessAddress GetAliasRegionStart() const {
return m_alias_region_start;
}
constexpr VAddr GetAliasRegionEnd() const {
constexpr KProcessAddress GetAliasRegionEnd() const {
return m_alias_region_end;
}
constexpr size_t GetAliasRegionSize() const {
return m_alias_region_end - m_alias_region_start;
}
constexpr VAddr GetStackRegionStart() const {
constexpr KProcessAddress GetStackRegionStart() const {
return m_stack_region_start;
}
constexpr VAddr GetStackRegionEnd() const {
constexpr KProcessAddress GetStackRegionEnd() const {
return m_stack_region_end;
}
constexpr size_t GetStackRegionSize() const {
return m_stack_region_end - m_stack_region_start;
}
constexpr VAddr GetKernelMapRegionStart() const {
constexpr KProcessAddress GetKernelMapRegionStart() const {
return m_kernel_map_region_start;
}
constexpr VAddr GetKernelMapRegionEnd() const {
constexpr KProcessAddress GetKernelMapRegionEnd() const {
return m_kernel_map_region_end;
}
constexpr VAddr GetCodeRegionStart() const {
constexpr KProcessAddress GetCodeRegionStart() const {
return m_code_region_start;
}
constexpr VAddr GetCodeRegionEnd() const {
constexpr KProcessAddress GetCodeRegionEnd() const {
return m_code_region_end;
}
constexpr VAddr GetAliasCodeRegionStart() const {
constexpr KProcessAddress GetAliasCodeRegionStart() const {
return m_alias_code_region_start;
}
constexpr VAddr GetAliasCodeRegionEnd() const {
constexpr KProcessAddress GetAliasCodeRegionEnd() const {
return m_alias_code_region_end;
}
constexpr VAddr GetAliasCodeRegionSize() const {
constexpr size_t GetAliasCodeRegionSize() const {
return m_alias_code_region_end - m_alias_code_region_start;
}
size_t GetNormalMemorySize() {
@@ -382,25 +387,25 @@ public:
constexpr size_t GetHeapSize() const {
return m_current_heap_end - m_heap_region_start;
}
constexpr bool IsInsideAddressSpace(VAddr address, size_t size) const {
constexpr bool IsInsideAddressSpace(KProcessAddress address, size_t size) const {
return m_address_space_start <= address && address + size - 1 <= m_address_space_end - 1;
}
constexpr bool IsOutsideAliasRegion(VAddr address, size_t size) const {
constexpr bool IsOutsideAliasRegion(KProcessAddress address, size_t size) const {
return m_alias_region_start > address || address + size - 1 > m_alias_region_end - 1;
}
constexpr bool IsOutsideStackRegion(VAddr address, size_t size) const {
constexpr bool IsOutsideStackRegion(KProcessAddress address, size_t size) const {
return m_stack_region_start > address || address + size - 1 > m_stack_region_end - 1;
}
constexpr bool IsInvalidRegion(VAddr address, size_t size) const {
constexpr bool IsInvalidRegion(KProcessAddress address, size_t size) const {
return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1;
}
constexpr bool IsInsideHeapRegion(VAddr address, size_t size) const {
constexpr bool IsInsideHeapRegion(KProcessAddress address, size_t size) const {
return address + size > m_heap_region_start && m_heap_region_end > address;
}
constexpr bool IsInsideAliasRegion(VAddr address, size_t size) const {
constexpr bool IsInsideAliasRegion(KProcessAddress address, size_t size) const {
return address + size > m_alias_region_start && m_alias_region_end > address;
}
constexpr bool IsOutsideASLRRegion(VAddr address, size_t size) const {
constexpr bool IsOutsideASLRRegion(KProcessAddress address, size_t size) const {
if (IsInvalidRegion(address, size)) {
return true;
}
@@ -412,47 +417,53 @@ public:
}
return {};
}
constexpr bool IsInsideASLRRegion(VAddr address, size_t size) const {
constexpr bool IsInsideASLRRegion(KProcessAddress address, size_t size) const {
return !IsOutsideASLRRegion(address, size);
}
constexpr size_t GetNumGuardPages() const {
return IsKernel() ? 1 : 4;
}
PAddr GetPhysicalAddr(VAddr addr) const {
KPhysicalAddress GetPhysicalAddr(KProcessAddress addr) const {
const auto backing_addr = m_page_table_impl->backing_addr[addr >> PageBits];
ASSERT(backing_addr);
return backing_addr + addr;
return backing_addr + GetInteger(addr);
}
constexpr bool Contains(VAddr addr) const {
constexpr bool Contains(KProcessAddress addr) const {
return m_address_space_start <= addr && addr <= m_address_space_end - 1;
}
constexpr bool Contains(VAddr addr, size_t size) const {
constexpr bool Contains(KProcessAddress addr, size_t size) const {
return m_address_space_start <= addr && addr < addr + size &&
addr + size - 1 <= m_address_space_end - 1;
}
public:
static VAddr GetLinearMappedVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
static KVirtualAddress GetLinearMappedVirtualAddress(const KMemoryLayout& layout,
KPhysicalAddress addr) {
return layout.GetLinearVirtualAddress(addr);
}
static PAddr GetLinearMappedPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
static KPhysicalAddress GetLinearMappedPhysicalAddress(const KMemoryLayout& layout,
KVirtualAddress addr) {
return layout.GetLinearPhysicalAddress(addr);
}
static VAddr GetHeapVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
static KVirtualAddress GetHeapVirtualAddress(const KMemoryLayout& layout,
KPhysicalAddress addr) {
return GetLinearMappedVirtualAddress(layout, addr);
}
static PAddr GetHeapPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
static KPhysicalAddress GetHeapPhysicalAddress(const KMemoryLayout& layout,
KVirtualAddress addr) {
return GetLinearMappedPhysicalAddress(layout, addr);
}
static VAddr GetPageTableVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
static KVirtualAddress GetPageTableVirtualAddress(const KMemoryLayout& layout,
KPhysicalAddress addr) {
return GetLinearMappedVirtualAddress(layout, addr);
}
static PAddr GetPageTablePhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
static KPhysicalAddress GetPageTablePhysicalAddress(const KMemoryLayout& layout,
KVirtualAddress addr) {
return GetLinearMappedPhysicalAddress(layout, addr);
}
@@ -464,7 +475,7 @@ private:
return m_enable_aslr;
}
constexpr bool ContainsPages(VAddr addr, size_t num_pages) const {
constexpr bool ContainsPages(KProcessAddress addr, size_t num_pages) const {
return (m_address_space_start <= addr) &&
(num_pages <= (m_address_space_end - m_address_space_start) / PageSize) &&
(addr + num_pages * PageSize - 1 <= m_address_space_end - 1);
@@ -484,26 +495,26 @@ private:
}
PageLinkedList* GetPageList() {
return &m_ll;
return std::addressof(m_ll);
}
};
private:
VAddr m_address_space_start{};
VAddr m_address_space_end{};
VAddr m_heap_region_start{};
VAddr m_heap_region_end{};
VAddr m_current_heap_end{};
VAddr m_alias_region_start{};
VAddr m_alias_region_end{};
VAddr m_stack_region_start{};
VAddr m_stack_region_end{};
VAddr m_kernel_map_region_start{};
VAddr m_kernel_map_region_end{};
VAddr m_code_region_start{};
VAddr m_code_region_end{};
VAddr m_alias_code_region_start{};
VAddr m_alias_code_region_end{};
KProcessAddress m_address_space_start{};
KProcessAddress m_address_space_end{};
KProcessAddress m_heap_region_start{};
KProcessAddress m_heap_region_end{};
KProcessAddress m_current_heap_end{};
KProcessAddress m_alias_region_start{};
KProcessAddress m_alias_region_end{};
KProcessAddress m_stack_region_start{};
KProcessAddress m_stack_region_end{};
KProcessAddress m_kernel_map_region_start{};
KProcessAddress m_kernel_map_region_end{};
KProcessAddress m_code_region_start{};
KProcessAddress m_code_region_end{};
KProcessAddress m_alias_code_region_start{};
KProcessAddress m_alias_code_region_end{};
size_t m_max_heap_size{};
size_t m_mapped_physical_memory_size{};

View File

@@ -5,9 +5,9 @@
#include <atomic>
#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
#include "core/hle/kernel/k_page_table_slab_heap.h"
#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
@@ -26,23 +26,23 @@ public:
BaseHeap::Initialize(page_allocator, pt_heap);
}
VAddr Allocate() {
return VAddr(BaseHeap::Allocate());
KVirtualAddress Allocate() {
return KVirtualAddress(BaseHeap::Allocate());
}
RefCount GetRefCount(VAddr addr) const {
RefCount GetRefCount(KVirtualAddress addr) const {
return m_pt_heap->GetRefCount(addr);
}
void Open(VAddr addr, int count) {
void Open(KVirtualAddress addr, int count) {
return m_pt_heap->Open(addr, count);
}
bool Close(VAddr addr, int count) {
bool Close(KVirtualAddress addr, int count) {
return m_pt_heap->Close(addr, count);
}
bool IsInPageTableHeap(VAddr addr) const {
bool IsInPageTableHeap(KVirtualAddress addr) const {
return m_pt_heap->IsInRange(addr);
}

View File

@@ -6,8 +6,8 @@
#include <array>
#include <vector>
#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_slab_heap.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
@@ -20,7 +20,8 @@ public:
PageTablePage() = default;
private:
std::array<u8, PageSize> m_buffer{};
// Initializer intentionally skipped
std::array<u8, PageSize> m_buffer;
};
static_assert(sizeof(PageTablePage) == PageSize);
@@ -44,12 +45,12 @@ public:
this->Initialize(rc);
}
RefCount GetRefCount(VAddr addr) {
RefCount GetRefCount(KVirtualAddress addr) {
ASSERT(this->IsInRange(addr));
return *this->GetRefCountPointer(addr);
}
void Open(VAddr addr, int count) {
void Open(KVirtualAddress addr, int count) {
ASSERT(this->IsInRange(addr));
*this->GetRefCountPointer(addr) += static_cast<RefCount>(count);
@@ -57,7 +58,7 @@ public:
ASSERT(this->GetRefCount(addr) > 0);
}
bool Close(VAddr addr, int count) {
bool Close(KVirtualAddress addr, int count) {
ASSERT(this->IsInRange(addr));
ASSERT(this->GetRefCount(addr) >= count);
@@ -65,7 +66,7 @@ public:
return this->GetRefCount(addr) == 0;
}
bool IsInPageTableHeap(VAddr addr) const {
bool IsInPageTableHeap(KVirtualAddress addr) const {
return this->IsInRange(addr);
}
@@ -80,7 +81,7 @@ private:
}
}
RefCount* GetRefCountPointer(VAddr addr) {
RefCount* GetRefCountPointer(KVirtualAddress addr) {
return m_ref_counts.data() + ((addr - this->GetAddress()) / PageSize);
}

View File

@@ -7,56 +7,55 @@
namespace Kernel {
KPort::KPort(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
KPort::KPort(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_server{kernel}, m_client{kernel} {}
KPort::~KPort() = default;
void KPort::Initialize(s32 max_sessions_, bool is_light_, const std::string& name_) {
void KPort::Initialize(s32 max_sessions, bool is_light, uintptr_t name) {
// Open a new reference count to the initialized port.
Open();
this->Open();
// Create and initialize our server/client pair.
KAutoObject::Create(std::addressof(server));
KAutoObject::Create(std::addressof(client));
server.Initialize(this, name_ + ":Server");
client.Initialize(this, max_sessions_, name_ + ":Client");
KAutoObject::Create(std::addressof(m_server));
KAutoObject::Create(std::addressof(m_client));
m_server.Initialize(this);
m_client.Initialize(this, max_sessions);
// Set our member variables.
is_light = is_light_;
name = name_;
state = State::Normal;
m_is_light = is_light;
m_name = name;
m_state = State::Normal;
}
void KPort::OnClientClosed() {
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (state == State::Normal) {
state = State::ClientClosed;
if (m_state == State::Normal) {
m_state = State::ClientClosed;
}
}
void KPort::OnServerClosed() {
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (state == State::Normal) {
state = State::ServerClosed;
if (m_state == State::Normal) {
m_state = State::ServerClosed;
}
}
bool KPort::IsServerClosed() const {
KScopedSchedulerLock sl{kernel};
return state == State::ServerClosed;
KScopedSchedulerLock sl{m_kernel};
return m_state == State::ServerClosed;
}
Result KPort::EnqueueSession(KServerSession* session) {
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
R_UNLESS(state == State::Normal, ResultPortClosed);
R_UNLESS(m_state == State::Normal, ResultPortClosed);
server.EnqueueSession(session);
return ResultSuccess;
m_server.EnqueueSession(session);
R_SUCCEED();
}
} // namespace Kernel

View File

@@ -19,17 +19,20 @@ class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjec
KERNEL_AUTOOBJECT_TRAITS(KPort, KAutoObject);
public:
explicit KPort(KernelCore& kernel_);
explicit KPort(KernelCore& kernel);
~KPort() override;
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
static void PostDestroy(uintptr_t arg) {}
void Initialize(s32 max_sessions_, bool is_light_, const std::string& name_);
void Initialize(s32 max_sessions, bool is_light, uintptr_t name);
void OnClientClosed();
void OnServerClosed();
uintptr_t GetName() const {
return m_name;
}
bool IsLight() const {
return is_light;
return m_is_light;
}
bool IsServerClosed() const;
@@ -37,16 +40,16 @@ public:
Result EnqueueSession(KServerSession* session);
KClientPort& GetClientPort() {
return client;
return m_client;
}
KServerPort& GetServerPort() {
return server;
return m_server;
}
const KClientPort& GetClientPort() const {
return client;
return m_client;
}
const KServerPort& GetServerPort() const {
return server;
return m_server;
}
private:
@@ -57,10 +60,11 @@ private:
ServerClosed = 3,
};
KServerPort server;
KClientPort client;
State state{State::Invalid};
bool is_light{};
KServerPort m_server;
KClientPort m_client;
uintptr_t m_name;
State m_state{State::Invalid};
bool m_is_light{};
};
} // namespace Kernel

View File

@@ -77,11 +77,11 @@ private:
public:
class KPerCoreQueue {
private:
std::array<Entry, NumCores> root{};
std::array<Entry, NumCores> m_root{};
public:
constexpr KPerCoreQueue() {
for (auto& per_core_root : root) {
for (auto& per_core_root : m_root) {
per_core_root.Initialize();
}
}
@@ -91,15 +91,15 @@ public:
Entry& member_entry = member->GetPriorityQueueEntry(core);
// Get the entry associated with the end of the queue.
Member* tail = this->root[core].GetPrev();
Member* tail = m_root[core].GetPrev();
Entry& tail_entry =
(tail != nullptr) ? tail->GetPriorityQueueEntry(core) : this->root[core];
(tail != nullptr) ? tail->GetPriorityQueueEntry(core) : m_root[core];
// Link the entries.
member_entry.SetPrev(tail);
member_entry.SetNext(nullptr);
tail_entry.SetNext(member);
this->root[core].SetPrev(member);
m_root[core].SetPrev(member);
return tail == nullptr;
}
@@ -109,15 +109,15 @@ public:
Entry& member_entry = member->GetPriorityQueueEntry(core);
// Get the entry associated with the front of the queue.
Member* head = this->root[core].GetNext();
Member* head = m_root[core].GetNext();
Entry& head_entry =
(head != nullptr) ? head->GetPriorityQueueEntry(core) : this->root[core];
(head != nullptr) ? head->GetPriorityQueueEntry(core) : m_root[core];
// Link the entries.
member_entry.SetPrev(nullptr);
member_entry.SetNext(head);
head_entry.SetPrev(member);
this->root[core].SetNext(member);
m_root[core].SetNext(member);
return (head == nullptr);
}
@@ -130,9 +130,9 @@ public:
Member* prev = member_entry.GetPrev();
Member* next = member_entry.GetNext();
Entry& prev_entry =
(prev != nullptr) ? prev->GetPriorityQueueEntry(core) : this->root[core];
(prev != nullptr) ? prev->GetPriorityQueueEntry(core) : m_root[core];
Entry& next_entry =
(next != nullptr) ? next->GetPriorityQueueEntry(core) : this->root[core];
(next != nullptr) ? next->GetPriorityQueueEntry(core) : m_root[core];
// Unlink.
prev_entry.SetNext(next);
@@ -142,7 +142,7 @@ public:
}
constexpr Member* GetFront(s32 core) const {
return this->root[core].GetNext();
return m_root[core].GetNext();
}
};
@@ -158,8 +158,8 @@ public:
return;
}
if (this->queues[priority].PushBack(core, member)) {
this->available_priorities[core].SetBit(priority);
if (m_queues[priority].PushBack(core, member)) {
m_available_priorities[core].SetBit(priority);
}
}
@@ -171,8 +171,8 @@ public:
return;
}
if (this->queues[priority].PushFront(core, member)) {
this->available_priorities[core].SetBit(priority);
if (m_queues[priority].PushFront(core, member)) {
m_available_priorities[core].SetBit(priority);
}
}
@@ -184,18 +184,17 @@ public:
return;
}
if (this->queues[priority].Remove(core, member)) {
this->available_priorities[core].ClearBit(priority);
if (m_queues[priority].Remove(core, member)) {
m_available_priorities[core].ClearBit(priority);
}
}
constexpr Member* GetFront(s32 core) const {
ASSERT(IsValidCore(core));
const s32 priority =
static_cast<s32>(this->available_priorities[core].CountLeadingZero());
const s32 priority = static_cast<s32>(m_available_priorities[core].CountLeadingZero());
if (priority <= LowestPriority) {
return this->queues[priority].GetFront(core);
return m_queues[priority].GetFront(core);
} else {
return nullptr;
}
@@ -206,7 +205,7 @@ public:
ASSERT(IsValidPriority(priority));
if (priority <= LowestPriority) {
return this->queues[priority].GetFront(core);
return m_queues[priority].GetFront(core);
} else {
return nullptr;
}
@@ -218,9 +217,9 @@ public:
Member* next = member->GetPriorityQueueEntry(core).GetNext();
if (next == nullptr) {
const s32 priority = static_cast<s32>(
this->available_priorities[core].GetNextSet(member->GetPriority()));
m_available_priorities[core].GetNextSet(member->GetPriority()));
if (priority <= LowestPriority) {
next = this->queues[priority].GetFront(core);
next = m_queues[priority].GetFront(core);
}
}
return next;
@@ -231,8 +230,8 @@ public:
ASSERT(IsValidPriority(priority));
if (priority <= LowestPriority) {
this->queues[priority].Remove(core, member);
this->queues[priority].PushFront(core, member);
m_queues[priority].Remove(core, member);
m_queues[priority].PushFront(core, member);
}
}
@@ -241,29 +240,29 @@ public:
ASSERT(IsValidPriority(priority));
if (priority <= LowestPriority) {
this->queues[priority].Remove(core, member);
this->queues[priority].PushBack(core, member);
return this->queues[priority].GetFront(core);
m_queues[priority].Remove(core, member);
m_queues[priority].PushBack(core, member);
return m_queues[priority].GetFront(core);
} else {
return nullptr;
}
}
private:
std::array<KPerCoreQueue, NumPriority> queues{};
std::array<Common::BitSet64<NumPriority>, NumCores> available_priorities{};
std::array<KPerCoreQueue, NumPriority> m_queues{};
std::array<Common::BitSet64<NumPriority>, NumCores> m_available_priorities{};
};
private:
KPriorityQueueImpl scheduled_queue;
KPriorityQueueImpl suggested_queue;
KPriorityQueueImpl m_scheduled_queue;
KPriorityQueueImpl m_suggested_queue;
private:
constexpr void ClearAffinityBit(u64& affinity, s32 core) {
static constexpr void ClearAffinityBit(u64& affinity, s32 core) {
affinity &= ~(UINT64_C(1) << core);
}
constexpr s32 GetNextCore(u64& affinity) {
static constexpr s32 GetNextCore(u64& affinity) {
const s32 core = std::countr_zero(affinity);
ClearAffinityBit(affinity, core);
return core;
@@ -275,13 +274,13 @@ private:
// Push onto the scheduled queue for its core, if we can.
u64 affinity = member->GetAffinityMask().GetAffinityMask();
if (const s32 core = member->GetActiveCore(); core >= 0) {
this->scheduled_queue.PushBack(priority, core, member);
m_scheduled_queue.PushBack(priority, core, member);
ClearAffinityBit(affinity, core);
}
// And suggest the thread for all other cores.
while (affinity) {
this->suggested_queue.PushBack(priority, GetNextCore(affinity), member);
m_suggested_queue.PushBack(priority, GetNextCore(affinity), member);
}
}
@@ -291,14 +290,14 @@ private:
// Push onto the scheduled queue for its core, if we can.
u64 affinity = member->GetAffinityMask().GetAffinityMask();
if (const s32 core = member->GetActiveCore(); core >= 0) {
this->scheduled_queue.PushFront(priority, core, member);
m_scheduled_queue.PushFront(priority, core, member);
ClearAffinityBit(affinity, core);
}
// And suggest the thread for all other cores.
// Note: Nintendo pushes onto the back of the suggested queue, not the front.
while (affinity) {
this->suggested_queue.PushBack(priority, GetNextCore(affinity), member);
m_suggested_queue.PushBack(priority, GetNextCore(affinity), member);
}
}
@@ -308,13 +307,13 @@ private:
// Remove from the scheduled queue for its core.
u64 affinity = member->GetAffinityMask().GetAffinityMask();
if (const s32 core = member->GetActiveCore(); core >= 0) {
this->scheduled_queue.Remove(priority, core, member);
m_scheduled_queue.Remove(priority, core, member);
ClearAffinityBit(affinity, core);
}
// Remove from the suggested queue for all other cores.
while (affinity) {
this->suggested_queue.Remove(priority, GetNextCore(affinity), member);
m_suggested_queue.Remove(priority, GetNextCore(affinity), member);
}
}
@@ -323,27 +322,27 @@ public:
// Getters.
constexpr Member* GetScheduledFront(s32 core) const {
return this->scheduled_queue.GetFront(core);
return m_scheduled_queue.GetFront(core);
}
constexpr Member* GetScheduledFront(s32 core, s32 priority) const {
return this->scheduled_queue.GetFront(priority, core);
return m_scheduled_queue.GetFront(priority, core);
}
constexpr Member* GetSuggestedFront(s32 core) const {
return this->suggested_queue.GetFront(core);
return m_suggested_queue.GetFront(core);
}
constexpr Member* GetSuggestedFront(s32 core, s32 priority) const {
return this->suggested_queue.GetFront(priority, core);
return m_suggested_queue.GetFront(priority, core);
}
constexpr Member* GetScheduledNext(s32 core, const Member* member) const {
return this->scheduled_queue.GetNext(core, member);
return m_scheduled_queue.GetNext(core, member);
}
constexpr Member* GetSuggestedNext(s32 core, const Member* member) const {
return this->suggested_queue.GetNext(core, member);
return m_suggested_queue.GetNext(core, member);
}
constexpr Member* GetSamePriorityNext(s32 core, const Member* member) const {
@@ -375,7 +374,7 @@ public:
return;
}
this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
m_scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
}
constexpr KThread* MoveToScheduledBack(Member* member) {
@@ -384,8 +383,7 @@ public:
return {};
}
return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
member);
return m_scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), member);
}
// First class fancy operations.
@@ -425,9 +423,9 @@ public:
for (s32 core = 0; core < static_cast<s32>(NumCores); core++) {
if (prev_affinity.GetAffinity(core)) {
if (core == prev_core) {
this->scheduled_queue.Remove(priority, core, member);
m_scheduled_queue.Remove(priority, core, member);
} else {
this->suggested_queue.Remove(priority, core, member);
m_suggested_queue.Remove(priority, core, member);
}
}
}
@@ -436,9 +434,9 @@ public:
for (s32 core = 0; core < static_cast<s32>(NumCores); core++) {
if (new_affinity.GetAffinity(core)) {
if (core == new_core) {
this->scheduled_queue.PushBack(priority, core, member);
m_scheduled_queue.PushBack(priority, core, member);
} else {
this->suggested_queue.PushBack(priority, core, member);
m_suggested_queue.PushBack(priority, core, member);
}
}
}
@@ -458,22 +456,22 @@ public:
if (prev_core != new_core) {
// Remove from the scheduled queue for the previous core.
if (prev_core >= 0) {
this->scheduled_queue.Remove(priority, prev_core, member);
m_scheduled_queue.Remove(priority, prev_core, member);
}
// Remove from the suggested queue and add to the scheduled queue for the new core.
if (new_core >= 0) {
this->suggested_queue.Remove(priority, new_core, member);
m_suggested_queue.Remove(priority, new_core, member);
if (to_front) {
this->scheduled_queue.PushFront(priority, new_core, member);
m_scheduled_queue.PushFront(priority, new_core, member);
} else {
this->scheduled_queue.PushBack(priority, new_core, member);
m_scheduled_queue.PushBack(priority, new_core, member);
}
}
// Add to the suggested queue for the previous core.
if (prev_core >= 0) {
this->suggested_queue.PushBack(priority, prev_core, member);
m_suggested_queue.PushBack(priority, prev_core, member);
}
}
}

View File

@@ -36,22 +36,23 @@ namespace {
* @param owner_process The parent process for the main thread
* @param priority The priority to give the main thread
*/
void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) {
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority,
KProcessAddress stack_top) {
const KProcessAddress entry_point = owner_process.PageTable().GetCodeRegionStart();
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
KThread* thread = KThread::Create(system.Kernel());
SCOPE_EXIT({ thread->Close(); });
ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
owner_process.GetIdealCoreId(), &owner_process)
owner_process.GetIdealCoreId(),
std::addressof(owner_process))
.IsSuccess());
// Register 1 must be a handle to the main thread
Handle thread_handle{};
owner_process.GetHandleTable().Add(&thread_handle, thread);
owner_process.GetHandleTable().Add(std::addressof(thread_handle), thread);
thread->SetName("main");
thread->GetContext32().cpu_registers[0] = 0;
thread->GetContext64().cpu_registers[0] = 0;
thread->GetContext32().cpu_registers[1] = thread_handle;
@@ -71,32 +72,32 @@ Result KProcess::Initialize(KProcess* process, Core::System& system, std::string
auto& kernel = system.Kernel();
process->name = std::move(process_name);
process->resource_limit = res_limit;
process->system_resource_address = 0;
process->state = State::Created;
process->program_id = 0;
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
: kernel.CreateNewUserProcessID();
process->capabilities.InitializeForMetadatalessProcess();
process->is_initialized = true;
process->m_resource_limit = res_limit;
process->m_system_resource_address = 0;
process->m_state = State::Created;
process->m_program_id = 0;
process->m_process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
: kernel.CreateNewUserProcessID();
process->m_capabilities.InitializeForMetadatalessProcess();
process->m_is_initialized = true;
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
std::uniform_int_distribution<u64> distribution;
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
std::generate(process->m_random_entropy.begin(), process->m_random_entropy.end(),
[&] { return distribution(rng); });
kernel.AppendNewProcess(process);
// Clear remaining fields.
process->num_running_threads = 0;
process->is_signaled = false;
process->exception_thread = nullptr;
process->is_suspended = false;
process->schedule_count = 0;
process->is_handle_table_initialized = false;
process->m_num_running_threads = 0;
process->m_is_signaled = false;
process->m_exception_thread = nullptr;
process->m_is_suspended = false;
process->m_schedule_count = 0;
process->m_is_handle_table_initialized = false;
// Open a reference to the resource limit.
process->resource_limit->Open();
process->m_resource_limit->Open();
R_SUCCEED();
}
@@ -106,65 +107,65 @@ void KProcess::DoWorkerTaskImpl() {
}
KResourceLimit* KProcess::GetResourceLimit() const {
return resource_limit;
return m_resource_limit;
}
void KProcess::IncrementRunningThreadCount() {
ASSERT(num_running_threads.load() >= 0);
++num_running_threads;
ASSERT(m_num_running_threads.load() >= 0);
++m_num_running_threads;
}
void KProcess::DecrementRunningThreadCount() {
ASSERT(num_running_threads.load() > 0);
ASSERT(m_num_running_threads.load() > 0);
if (const auto prev = num_running_threads--; prev == 1) {
if (const auto prev = m_num_running_threads--; prev == 1) {
// TODO(bunnei): Process termination to be implemented when multiprocess is supported.
}
}
u64 KProcess::GetTotalPhysicalMemoryAvailable() {
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemoryMax) +
page_table.GetNormalMemorySize() + GetSystemResourceSize() + image_size +
main_thread_stack_size};
if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
const u64 capacity{m_resource_limit->GetFreeValue(LimitableResource::PhysicalMemoryMax) +
m_page_table.GetNormalMemorySize() + GetSystemResourceSize() + m_image_size +
m_main_thread_stack_size};
if (const auto pool_size = m_kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
capacity != pool_size) {
LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size);
}
if (capacity < memory_usage_capacity) {
if (capacity < m_memory_usage_capacity) {
return capacity;
}
return memory_usage_capacity;
return m_memory_usage_capacity;
}
u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() {
return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize();
return this->GetTotalPhysicalMemoryAvailable() - this->GetSystemResourceSize();
}
u64 KProcess::GetTotalPhysicalMemoryUsed() {
return image_size + main_thread_stack_size + page_table.GetNormalMemorySize() +
GetSystemResourceSize();
return m_image_size + m_main_thread_stack_size + m_page_table.GetNormalMemorySize() +
this->GetSystemResourceSize();
}
u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() {
return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceUsage();
}
bool KProcess::ReleaseUserException(KThread* thread) {
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (exception_thread == thread) {
exception_thread = nullptr;
if (m_exception_thread == thread) {
m_exception_thread = nullptr;
// Remove waiter thread.
bool has_waiters{};
if (KThread* next = thread->RemoveKernelWaiterByKey(
std::addressof(has_waiters),
reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)));
next != nullptr) {
next->EndWait(ResultSuccess);
}
KScheduler::SetSchedulerUpdateNeeded(kernel);
KScheduler::SetSchedulerUpdateNeeded(m_kernel);
return true;
} else {
@@ -173,72 +174,72 @@ bool KProcess::ReleaseUserException(KThread* thread) {
}
void KProcess::PinCurrentThread(s32 core_id) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Get the current thread.
KThread* cur_thread =
kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
m_kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
// If the thread isn't terminated, pin it.
if (!cur_thread->IsTerminationRequested()) {
// Pin it.
PinThread(core_id, cur_thread);
this->PinThread(core_id, cur_thread);
cur_thread->Pin(core_id);
// An update is needed.
KScheduler::SetSchedulerUpdateNeeded(kernel);
KScheduler::SetSchedulerUpdateNeeded(m_kernel);
}
}
void KProcess::UnpinCurrentThread(s32 core_id) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Get the current thread.
KThread* cur_thread =
kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
m_kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
// Unpin it.
cur_thread->Unpin();
UnpinThread(core_id, cur_thread);
this->UnpinThread(core_id, cur_thread);
// An update is needed.
KScheduler::SetSchedulerUpdateNeeded(kernel);
KScheduler::SetSchedulerUpdateNeeded(m_kernel);
}
void KProcess::UnpinThread(KThread* thread) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Get the thread's core id.
const auto core_id = thread->GetActiveCore();
// Unpin it.
UnpinThread(core_id, thread);
this->UnpinThread(core_id, thread);
thread->Unpin();
// An update is needed.
KScheduler::SetSchedulerUpdateNeeded(kernel);
KScheduler::SetSchedulerUpdateNeeded(m_kernel);
}
Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] KProcessAddress address,
[[maybe_unused]] size_t size) {
// Lock ourselves, to prevent concurrent access.
KScopedLightLock lk(state_lock);
KScopedLightLock lk(m_state_lock);
// Try to find an existing info for the memory.
KSharedMemoryInfo* shemen_info = nullptr;
const auto iter = std::find_if(
shared_memory_list.begin(), shared_memory_list.end(),
m_shared_memory_list.begin(), m_shared_memory_list.end(),
[shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
if (iter != shared_memory_list.end()) {
if (iter != m_shared_memory_list.end()) {
shemen_info = *iter;
}
if (shemen_info == nullptr) {
shemen_info = KSharedMemoryInfo::Allocate(kernel);
shemen_info = KSharedMemoryInfo::Allocate(m_kernel);
R_UNLESS(shemen_info != nullptr, ResultOutOfMemory);
shemen_info->Initialize(shmem);
shared_memory_list.push_back(shemen_info);
m_shared_memory_list.push_back(shemen_info);
}
// Open a reference to the shared memory and its info.
@@ -248,24 +249,24 @@ Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr ad
R_SUCCEED();
}
void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] KProcessAddress address,
[[maybe_unused]] size_t size) {
// Lock ourselves, to prevent concurrent access.
KScopedLightLock lk(state_lock);
KScopedLightLock lk(m_state_lock);
KSharedMemoryInfo* shemen_info = nullptr;
const auto iter = std::find_if(
shared_memory_list.begin(), shared_memory_list.end(),
m_shared_memory_list.begin(), m_shared_memory_list.end(),
[shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
if (iter != shared_memory_list.end()) {
if (iter != m_shared_memory_list.end()) {
shemen_info = *iter;
}
ASSERT(shemen_info != nullptr);
if (shemen_info->Close()) {
shared_memory_list.erase(iter);
KSharedMemoryInfo::Free(kernel, shemen_info);
m_shared_memory_list.erase(iter);
KSharedMemoryInfo::Free(m_kernel, shemen_info);
}
// Close a reference to the shared memory.
@@ -273,22 +274,22 @@ void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr a
}
void KProcess::RegisterThread(KThread* thread) {
KScopedLightLock lk{list_lock};
KScopedLightLock lk{m_list_lock};
thread_list.push_back(thread);
m_thread_list.push_back(thread);
}
void KProcess::UnregisterThread(KThread* thread) {
KScopedLightLock lk{list_lock};
KScopedLightLock lk{m_list_lock};
thread_list.remove(thread);
m_thread_list.remove(thread);
}
u64 KProcess::GetFreeThreadCount() const {
if (resource_limit != nullptr) {
if (m_resource_limit != nullptr) {
const auto current_value =
resource_limit->GetCurrentValue(LimitableResource::ThreadCountMax);
const auto limit_value = resource_limit->GetLimitValue(LimitableResource::ThreadCountMax);
m_resource_limit->GetCurrentValue(LimitableResource::ThreadCountMax);
const auto limit_value = m_resource_limit->GetLimitValue(LimitableResource::ThreadCountMax);
return limit_value - current_value;
} else {
return 0;
@@ -297,84 +298,85 @@ u64 KProcess::GetFreeThreadCount() const {
Result KProcess::Reset() {
// Lock the process and the scheduler.
KScopedLightLock lk(state_lock);
KScopedSchedulerLock sl{kernel};
KScopedLightLock lk(m_state_lock);
KScopedSchedulerLock sl{m_kernel};
// Validate that we're in a state that we can reset.
R_UNLESS(state != State::Terminated, ResultInvalidState);
R_UNLESS(is_signaled, ResultInvalidState);
R_UNLESS(m_state != State::Terminated, ResultInvalidState);
R_UNLESS(m_is_signaled, ResultInvalidState);
// Clear signaled.
is_signaled = false;
m_is_signaled = false;
R_SUCCEED();
}
Result KProcess::SetActivity(ProcessActivity activity) {
// Lock ourselves and the scheduler.
KScopedLightLock lk{state_lock};
KScopedLightLock list_lk{list_lock};
KScopedSchedulerLock sl{kernel};
KScopedLightLock lk{m_state_lock};
KScopedLightLock list_lk{m_list_lock};
KScopedSchedulerLock sl{m_kernel};
// Validate our state.
R_UNLESS(state != State::Terminating, ResultInvalidState);
R_UNLESS(state != State::Terminated, ResultInvalidState);
R_UNLESS(m_state != State::Terminating, ResultInvalidState);
R_UNLESS(m_state != State::Terminated, ResultInvalidState);
// Either pause or resume.
if (activity == ProcessActivity::Paused) {
// Verify that we're not suspended.
R_UNLESS(!is_suspended, ResultInvalidState);
R_UNLESS(!m_is_suspended, ResultInvalidState);
// Suspend all threads.
for (auto* thread : GetThreadList()) {
for (auto* thread : this->GetThreadList()) {
thread->RequestSuspend(SuspendType::Process);
}
// Set ourselves as suspended.
SetSuspended(true);
this->SetSuspended(true);
} else {
ASSERT(activity == ProcessActivity::Runnable);
// Verify that we're suspended.
R_UNLESS(is_suspended, ResultInvalidState);
R_UNLESS(m_is_suspended, ResultInvalidState);
// Resume all threads.
for (auto* thread : GetThreadList()) {
for (auto* thread : this->GetThreadList()) {
thread->Resume(SuspendType::Process);
}
// Set ourselves as resumed.
SetSuspended(false);
this->SetSuspended(false);
}
R_SUCCEED();
}
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size) {
program_id = metadata.GetTitleID();
ideal_core = metadata.GetMainThreadCore();
is_64bit_process = metadata.Is64BitProgram();
system_resource_size = metadata.GetSystemResourceSize();
image_size = code_size;
m_program_id = metadata.GetTitleID();
m_ideal_core = metadata.GetMainThreadCore();
m_is_64bit_process = metadata.Is64BitProgram();
m_system_resource_size = metadata.GetSystemResourceSize();
m_image_size = code_size;
KScopedResourceReservation memory_reservation(
resource_limit, LimitableResource::PhysicalMemoryMax, code_size + system_resource_size);
m_resource_limit, LimitableResource::PhysicalMemoryMax, code_size + m_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);
code_size + m_system_resource_size);
R_RETURN(ResultLimitReached);
}
// Initialize process address space
if (const Result result{page_table.InitializeForProcess(
if (const Result result{m_page_table.InitializeForProcess(
metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application,
0x8000000, code_size, &kernel.GetAppSystemResource(), resource_limit)};
0x8000000, code_size, std::addressof(m_kernel.GetAppSystemResource()),
m_resource_limit)};
result.IsError()) {
R_RETURN(result);
}
// Map process code region
if (const Result result{page_table.MapProcessCode(page_table.GetCodeRegionStart(),
code_size / PageSize, KMemoryState::Code,
KMemoryPermission::None)};
if (const Result result{m_page_table.MapProcessCode(m_page_table.GetCodeRegionStart(),
code_size / PageSize, KMemoryState::Code,
KMemoryPermission::None)};
result.IsError()) {
R_RETURN(result);
}
@@ -382,7 +384,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
// Initialize process capabilities
const auto& caps{metadata.GetKernelCapabilities()};
if (const Result result{
capabilities.InitializeForUserProcess(caps.data(), caps.size(), page_table)};
m_capabilities.InitializeForUserProcess(caps.data(), caps.size(), m_page_table)};
result.IsError()) {
R_RETURN(result);
}
@@ -392,12 +394,14 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
case FileSys::ProgramAddressSpaceType::Is32Bit:
case FileSys::ProgramAddressSpaceType::Is36Bit:
case FileSys::ProgramAddressSpaceType::Is39Bit:
memory_usage_capacity = page_table.GetHeapRegionEnd() - page_table.GetHeapRegionStart();
m_memory_usage_capacity =
m_page_table.GetHeapRegionEnd() - m_page_table.GetHeapRegionStart();
break;
case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
memory_usage_capacity = page_table.GetHeapRegionEnd() - page_table.GetHeapRegionStart() +
page_table.GetAliasRegionEnd() - page_table.GetAliasRegionStart();
m_memory_usage_capacity =
(m_page_table.GetHeapRegionEnd() - m_page_table.GetHeapRegionStart()) +
(m_page_table.GetAliasRegionEnd() - m_page_table.GetAliasRegionStart());
break;
default:
@@ -406,33 +410,34 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
}
// Create TLS region
R_TRY(this->CreateThreadLocalRegion(std::addressof(plr_address)));
R_TRY(this->CreateThreadLocalRegion(std::addressof(m_plr_address)));
memory_reservation.Commit();
R_RETURN(handle_table.Initialize(capabilities.GetHandleTableSize()));
R_RETURN(m_handle_table.Initialize(m_capabilities.GetHandleTableSize()));
}
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
ASSERT(AllocateMainThreadStack(stack_size) == ResultSuccess);
resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
ASSERT(this->AllocateMainThreadStack(stack_size) == ResultSuccess);
m_resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError());
const std::size_t heap_capacity{m_memory_usage_capacity -
(m_main_thread_stack_size + m_image_size)};
ASSERT(!m_page_table.SetMaxHeapSize(heap_capacity).IsError());
ChangeState(State::Running);
this->ChangeState(State::Running);
SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top);
SetupMainThread(m_kernel.System(), *this, main_thread_priority, m_main_thread_stack_top);
}
void KProcess::PrepareForTermination() {
ChangeState(State::Terminating);
this->ChangeState(State::Terminating);
const auto stop_threads = [this](const std::vector<KThread*>& in_thread_list) {
for (auto* thread : in_thread_list) {
if (thread->GetOwnerProcess() != this)
continue;
if (thread == GetCurrentThreadPointer(kernel))
if (thread == GetCurrentThreadPointer(m_kernel))
continue;
// TODO(Subv): When are the other running/ready threads terminated?
@@ -443,24 +448,24 @@ void KProcess::PrepareForTermination() {
}
};
stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList());
stop_threads(m_kernel.System().GlobalSchedulerContext().GetThreadList());
this->DeleteThreadLocalRegion(plr_address);
plr_address = 0;
this->DeleteThreadLocalRegion(m_plr_address);
m_plr_address = 0;
if (resource_limit) {
resource_limit->Release(LimitableResource::PhysicalMemoryMax,
main_thread_stack_size + image_size);
if (m_resource_limit) {
m_resource_limit->Release(LimitableResource::PhysicalMemoryMax,
m_main_thread_stack_size + m_image_size);
}
ChangeState(State::Terminated);
this->ChangeState(State::Terminated);
}
void KProcess::Finalize() {
// Free all shared memory infos.
{
auto it = shared_memory_list.begin();
while (it != shared_memory_list.end()) {
auto it = m_shared_memory_list.begin();
while (it != m_shared_memory_list.end()) {
KSharedMemoryInfo* info = *it;
KSharedMemory* shmem = info->GetSharedMemory();
@@ -470,40 +475,40 @@ void KProcess::Finalize() {
shmem->Close();
it = shared_memory_list.erase(it);
KSharedMemoryInfo::Free(kernel, info);
it = m_shared_memory_list.erase(it);
KSharedMemoryInfo::Free(m_kernel, info);
}
}
// Release memory to the resource limit.
if (resource_limit != nullptr) {
resource_limit->Close();
resource_limit = nullptr;
if (m_resource_limit != nullptr) {
m_resource_limit->Close();
m_resource_limit = nullptr;
}
// Finalize the page table.
page_table.Finalize();
m_page_table.Finalize();
// Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize();
KSynchronizationObject::Finalize();
}
Result KProcess::CreateThreadLocalRegion(VAddr* out) {
Result KProcess::CreateThreadLocalRegion(KProcessAddress* out) {
KThreadLocalPage* tlp = nullptr;
VAddr tlr = 0;
KProcessAddress tlr = 0;
// See if we can get a region from a partially used TLP.
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (auto it = partially_used_tlp_tree.begin(); it != partially_used_tlp_tree.end()) {
if (auto it = m_partially_used_tlp_tree.begin(); it != m_partially_used_tlp_tree.end()) {
tlr = it->Reserve();
ASSERT(tlr != 0);
if (it->IsAllUsed()) {
tlp = std::addressof(*it);
partially_used_tlp_tree.erase(it);
fully_used_tlp_tree.insert(*tlp);
m_partially_used_tlp_tree.erase(it);
m_fully_used_tlp_tree.insert(*tlp);
}
*out = tlr;
@@ -512,12 +517,12 @@ Result KProcess::CreateThreadLocalRegion(VAddr* out) {
}
// Allocate a new page.
tlp = KThreadLocalPage::Allocate(kernel);
tlp = KThreadLocalPage::Allocate(m_kernel);
R_UNLESS(tlp != nullptr, ResultOutOfMemory);
auto tlp_guard = SCOPE_GUARD({ KThreadLocalPage::Free(kernel, tlp); });
auto tlp_guard = SCOPE_GUARD({ KThreadLocalPage::Free(m_kernel, tlp); });
// Initialize the new page.
R_TRY(tlp->Initialize(kernel, this));
R_TRY(tlp->Initialize(m_kernel, this));
// Reserve a TLR.
tlr = tlp->Reserve();
@@ -525,11 +530,11 @@ Result KProcess::CreateThreadLocalRegion(VAddr* out) {
// Insert into our tree.
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (tlp->IsAllUsed()) {
fully_used_tlp_tree.insert(*tlp);
m_fully_used_tlp_tree.insert(*tlp);
} else {
partially_used_tlp_tree.insert(*tlp);
m_partially_used_tlp_tree.insert(*tlp);
}
}
@@ -539,30 +544,30 @@ Result KProcess::CreateThreadLocalRegion(VAddr* out) {
R_SUCCEED();
}
Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
Result KProcess::DeleteThreadLocalRegion(KProcessAddress addr) {
KThreadLocalPage* page_to_free = nullptr;
// Release the region.
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// Try to find the page in the partially used list.
auto it = partially_used_tlp_tree.find_key(Common::AlignDown(addr, PageSize));
if (it == partially_used_tlp_tree.end()) {
auto it = m_partially_used_tlp_tree.find_key(Common::AlignDown(GetInteger(addr), PageSize));
if (it == m_partially_used_tlp_tree.end()) {
// If we don't find it, it has to be in the fully used list.
it = fully_used_tlp_tree.find_key(Common::AlignDown(addr, PageSize));
R_UNLESS(it != fully_used_tlp_tree.end(), ResultInvalidAddress);
it = m_fully_used_tlp_tree.find_key(Common::AlignDown(GetInteger(addr), PageSize));
R_UNLESS(it != m_fully_used_tlp_tree.end(), ResultInvalidAddress);
// Release the region.
it->Release(addr);
// Move the page out of the fully used list.
KThreadLocalPage* tlp = std::addressof(*it);
fully_used_tlp_tree.erase(it);
m_fully_used_tlp_tree.erase(it);
if (tlp->IsAllFree()) {
page_to_free = tlp;
} else {
partially_used_tlp_tree.insert(*tlp);
m_partially_used_tlp_tree.insert(*tlp);
}
} else {
// Release the region.
@@ -571,7 +576,7 @@ Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
// Handle the all-free case.
KThreadLocalPage* tlp = std::addressof(*it);
if (tlp->IsAllFree()) {
partially_used_tlp_tree.erase(it);
m_partially_used_tlp_tree.erase(it);
page_to_free = tlp;
}
}
@@ -581,19 +586,19 @@ Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
if (page_to_free != nullptr) {
page_to_free->Finalize();
KThreadLocalPage::Free(kernel, page_to_free);
KThreadLocalPage::Free(m_kernel, page_to_free);
}
R_SUCCEED();
}
bool KProcess::InsertWatchpoint(Core::System& system, VAddr addr, u64 size,
bool KProcess::InsertWatchpoint(Core::System& system, KProcessAddress addr, u64 size,
DebugWatchpointType type) {
const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) {
const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) {
return wp.type == DebugWatchpointType::None;
})};
if (watch == watchpoints.end()) {
if (watch == m_watchpoints.end()) {
return false;
}
@@ -601,21 +606,22 @@ bool KProcess::InsertWatchpoint(Core::System& system, VAddr addr, u64 size,
watch->end_address = addr + size;
watch->type = type;
for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) {
debug_page_refcounts[page]++;
for (KProcessAddress page = Common::AlignDown(GetInteger(addr), PageSize); page < addr + size;
page += PageSize) {
m_debug_page_refcounts[page]++;
system.Memory().MarkRegionDebug(page, PageSize, true);
}
return true;
}
bool KProcess::RemoveWatchpoint(Core::System& system, VAddr addr, u64 size,
bool KProcess::RemoveWatchpoint(Core::System& system, KProcessAddress addr, u64 size,
DebugWatchpointType type) {
const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) {
const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) {
return wp.start_address == addr && wp.end_address == addr + size && wp.type == type;
})};
if (watch == watchpoints.end()) {
if (watch == m_watchpoints.end()) {
return false;
}
@@ -623,9 +629,10 @@ bool KProcess::RemoveWatchpoint(Core::System& system, VAddr addr, u64 size,
watch->end_address = 0;
watch->type = DebugWatchpointType::None;
for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) {
debug_page_refcounts[page]--;
if (!debug_page_refcounts[page]) {
for (KProcessAddress page = Common::AlignDown(GetInteger(addr), PageSize); page < addr + size;
page += PageSize) {
m_debug_page_refcounts[page]--;
if (!m_debug_page_refcounts[page]) {
system.Memory().MarkRegionDebug(page, PageSize, false);
}
}
@@ -633,14 +640,14 @@ bool KProcess::RemoveWatchpoint(Core::System& system, VAddr addr, u64 size,
return true;
}
void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
Svc::MemoryPermission permission) {
page_table.SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
m_page_table.SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
};
kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
code_set.memory.size());
m_kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
code_set.memory.size());
ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute);
ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read);
@@ -648,35 +655,35 @@ void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
}
bool KProcess::IsSignaled() const {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
return is_signaled;
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
return m_is_signaled;
}
KProcess::KProcess(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, page_table{kernel_.System()},
handle_table{kernel_}, address_arbiter{kernel_.System()}, condition_var{kernel_.System()},
state_lock{kernel_}, list_lock{kernel_} {}
KProcess::KProcess(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_page_table{m_kernel.System()},
m_handle_table{m_kernel}, m_address_arbiter{m_kernel.System()},
m_condition_var{m_kernel.System()}, m_state_lock{m_kernel}, m_list_lock{m_kernel} {}
KProcess::~KProcess() = default;
void KProcess::ChangeState(State new_state) {
if (state == new_state) {
if (m_state == new_state) {
return;
}
state = new_state;
is_signaled = true;
NotifyAvailable();
m_state = new_state;
m_is_signaled = true;
this->NotifyAvailable();
}
Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
// Ensure that we haven't already allocated stack.
ASSERT(main_thread_stack_size == 0);
ASSERT(m_main_thread_stack_size == 0);
// Ensure that we're allocating a valid stack.
stack_size = Common::AlignUp(stack_size, PageSize);
// R_UNLESS(stack_size + image_size <= m_max_process_memory, ResultOutOfMemory);
R_UNLESS(stack_size + image_size >= image_size, ResultOutOfMemory);
R_UNLESS(stack_size + m_image_size >= m_image_size, ResultOutOfMemory);
// Place a tentative reservation of memory for our new stack.
KScopedResourceReservation mem_reservation(this, Svc::LimitableResource::PhysicalMemoryMax,
@@ -686,11 +693,11 @@ Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
// Allocate and map our stack.
if (stack_size) {
KProcessAddress stack_bottom;
R_TRY(page_table.MapPages(std::addressof(stack_bottom), stack_size / PageSize,
KMemoryState::Stack, KMemoryPermission::UserReadWrite));
R_TRY(m_page_table.MapPages(std::addressof(stack_bottom), stack_size / PageSize,
KMemoryState::Stack, KMemoryPermission::UserReadWrite));
main_thread_stack_top = stack_bottom + stack_size;
main_thread_stack_size = stack_size;
m_main_thread_stack_top = stack_bottom + stack_size;
m_main_thread_stack_size = stack_size;
}
// We succeeded! Commit our memory reservation.

View File

@@ -8,7 +8,6 @@
#include <list>
#include <map>
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_condition_variable.h"
@@ -16,6 +15,7 @@
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread_local_page.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/k_worker_task.h"
#include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/slab_helpers.h"
@@ -59,8 +59,8 @@ enum class DebugWatchpointType : u8 {
DECLARE_ENUM_FLAG_OPERATORS(DebugWatchpointType);
struct DebugWatchpoint {
VAddr start_address;
VAddr end_address;
KProcessAddress start_address;
KProcessAddress end_address;
DebugWatchpointType type;
};
@@ -68,7 +68,7 @@ class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWor
KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
public:
explicit KProcess(KernelCore& kernel_);
explicit KProcess(KernelCore& kernel);
~KProcess() override;
enum class State {
@@ -107,66 +107,77 @@ public:
/// Gets a reference to the process' page table.
KPageTable& PageTable() {
return page_table;
return m_page_table;
}
/// Gets const a reference to the process' page table.
const KPageTable& PageTable() const {
return page_table;
return m_page_table;
}
/// Gets a reference to the process' page table.
KPageTable& GetPageTable() {
return m_page_table;
}
/// Gets const a reference to the process' page table.
const KPageTable& GetPageTable() const {
return m_page_table;
}
/// Gets a reference to the process' handle table.
KHandleTable& GetHandleTable() {
return handle_table;
return m_handle_table;
}
/// Gets a const reference to the process' handle table.
const KHandleTable& GetHandleTable() const {
return handle_table;
return m_handle_table;
}
Result SignalToAddress(VAddr address) {
return condition_var.SignalToAddress(address);
Result SignalToAddress(KProcessAddress address) {
return m_condition_var.SignalToAddress(address);
}
Result WaitForAddress(Handle handle, VAddr address, u32 tag) {
return condition_var.WaitForAddress(handle, address, tag);
Result WaitForAddress(Handle handle, KProcessAddress address, u32 tag) {
return m_condition_var.WaitForAddress(handle, address, tag);
}
void SignalConditionVariable(u64 cv_key, int32_t count) {
return condition_var.Signal(cv_key, count);
return m_condition_var.Signal(cv_key, count);
}
Result WaitConditionVariable(VAddr address, u64 cv_key, u32 tag, s64 ns) {
R_RETURN(condition_var.Wait(address, cv_key, tag, ns));
Result WaitConditionVariable(KProcessAddress address, u64 cv_key, u32 tag, s64 ns) {
R_RETURN(m_condition_var.Wait(address, cv_key, tag, ns));
}
Result SignalAddressArbiter(VAddr address, Svc::SignalType signal_type, s32 value, s32 count) {
R_RETURN(address_arbiter.SignalToAddress(address, signal_type, value, count));
Result SignalAddressArbiter(uint64_t address, Svc::SignalType signal_type, s32 value,
s32 count) {
R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count));
}
Result WaitAddressArbiter(VAddr address, Svc::ArbitrationType arb_type, s32 value,
Result WaitAddressArbiter(uint64_t address, Svc::ArbitrationType arb_type, s32 value,
s64 timeout) {
R_RETURN(address_arbiter.WaitForAddress(address, arb_type, value, timeout));
R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout));
}
VAddr GetProcessLocalRegionAddress() const {
return plr_address;
KProcessAddress GetProcessLocalRegionAddress() const {
return m_plr_address;
}
/// Gets the current status of the process
State GetState() const {
return state;
return m_state;
}
/// Gets the unique ID that identifies this particular process.
u64 GetProcessID() const {
return process_id;
u64 GetProcessId() const {
return m_process_id;
}
/// Gets the program ID corresponding to this process.
u64 GetProgramID() const {
return program_id;
u64 GetProgramId() const {
return m_program_id;
}
/// Gets the resource limit descriptor for this process
@@ -174,7 +185,7 @@ public:
/// Gets the ideal CPU core ID for this process
u8 GetIdealCoreId() const {
return ideal_core;
return m_ideal_core;
}
/// Checks if the specified thread priority is valid.
@@ -184,17 +195,17 @@ public:
/// Gets the bitmask of allowed cores that this process' threads can run on.
u64 GetCoreMask() const {
return capabilities.GetCoreMask();
return m_capabilities.GetCoreMask();
}
/// Gets the bitmask of allowed thread priorities.
u64 GetPriorityMask() const {
return capabilities.GetPriorityMask();
return m_capabilities.GetPriorityMask();
}
/// Gets the amount of secure memory to allocate for memory management.
u32 GetSystemResourceSize() const {
return system_resource_size;
return m_system_resource_size;
}
/// Gets the amount of secure memory currently in use for memory management.
@@ -214,67 +225,67 @@ public:
/// Whether this process is an AArch64 or AArch32 process.
bool Is64BitProcess() const {
return is_64bit_process;
return m_is_64bit_process;
}
[[nodiscard]] bool IsSuspended() const {
return is_suspended;
bool IsSuspended() const {
return m_is_suspended;
}
void SetSuspended(bool suspended) {
is_suspended = suspended;
m_is_suspended = suspended;
}
/// Gets the total running time of the process instance in ticks.
u64 GetCPUTimeTicks() const {
return total_process_running_time_ticks;
return m_total_process_running_time_ticks;
}
/// Updates the total running time, adding the given ticks to it.
void UpdateCPUTimeTicks(u64 ticks) {
total_process_running_time_ticks += ticks;
m_total_process_running_time_ticks += ticks;
}
/// Gets the process schedule count, used for thread yielding
s64 GetScheduledCount() const {
return schedule_count;
return m_schedule_count;
}
/// Increments the process schedule count, used for thread yielding.
void IncrementScheduledCount() {
++schedule_count;
++m_schedule_count;
}
void IncrementRunningThreadCount();
void DecrementRunningThreadCount();
void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
running_threads[core] = thread;
running_thread_idle_counts[core] = idle_count;
m_running_threads[core] = thread;
m_running_thread_idle_counts[core] = idle_count;
}
void ClearRunningThread(KThread* thread) {
for (size_t i = 0; i < running_threads.size(); ++i) {
if (running_threads[i] == thread) {
running_threads[i] = nullptr;
for (size_t i = 0; i < m_running_threads.size(); ++i) {
if (m_running_threads[i] == thread) {
m_running_threads[i] = nullptr;
}
}
}
[[nodiscard]] KThread* GetRunningThread(s32 core) const {
return running_threads[core];
return m_running_threads[core];
}
bool ReleaseUserException(KThread* thread);
[[nodiscard]] KThread* GetPinnedThread(s32 core_id) const {
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
return pinned_threads[core_id];
return m_pinned_threads[core_id];
}
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
u64 GetRandomEntropy(std::size_t index) const {
return random_entropy.at(index);
return m_random_entropy.at(index);
}
/// Retrieves the total physical memory available to this process in bytes.
@@ -293,7 +304,7 @@ public:
/// Gets the list of all threads created with this process as their owner.
std::list<KThread*>& GetThreadList() {
return thread_list;
return m_thread_list;
}
/// Registers a thread as being created under this process,
@@ -342,18 +353,18 @@ public:
*/
void PrepareForTermination();
void LoadModule(CodeSet code_set, VAddr base_addr);
void LoadModule(CodeSet code_set, KProcessAddress base_addr);
bool IsInitialized() const override {
return is_initialized;
return m_is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
static void PostDestroy(uintptr_t arg) {}
void Finalize() override;
u64 GetId() const override {
return GetProcessID();
return GetProcessId();
}
bool IsSignaled() const override;
@@ -367,55 +378,61 @@ public:
void UnpinThread(KThread* thread);
KLightLock& GetStateLock() {
return state_lock;
return m_state_lock;
}
Result AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
Result AddSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size);
void RemoveSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size);
///////////////////////////////////////////////////////////////////////////////////////////////
// Thread-local storage management
// Marks the next available region as used and returns the address of the slot.
[[nodiscard]] Result CreateThreadLocalRegion(VAddr* out);
[[nodiscard]] Result CreateThreadLocalRegion(KProcessAddress* out);
// Frees a used TLS slot identified by the given address
Result DeleteThreadLocalRegion(VAddr addr);
Result DeleteThreadLocalRegion(KProcessAddress addr);
///////////////////////////////////////////////////////////////////////////////////////////////
// Debug watchpoint management
// Attempts to insert a watchpoint into a free slot. Returns false if none are available.
bool InsertWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type);
bool InsertWatchpoint(Core::System& system, KProcessAddress addr, u64 size,
DebugWatchpointType type);
// Attempts to remove the watchpoint specified by the given parameters.
bool RemoveWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type);
bool RemoveWatchpoint(Core::System& system, KProcessAddress addr, u64 size,
DebugWatchpointType type);
const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const {
return watchpoints;
return m_watchpoints;
}
const std::string& GetName() {
return name;
}
private:
void PinThread(s32 core_id, KThread* thread) {
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
ASSERT(thread != nullptr);
ASSERT(pinned_threads[core_id] == nullptr);
pinned_threads[core_id] = thread;
ASSERT(m_pinned_threads[core_id] == nullptr);
m_pinned_threads[core_id] = thread;
}
void UnpinThread(s32 core_id, KThread* thread) {
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
ASSERT(thread != nullptr);
ASSERT(pinned_threads[core_id] == thread);
pinned_threads[core_id] = nullptr;
ASSERT(m_pinned_threads[core_id] == thread);
m_pinned_threads[core_id] = nullptr;
}
void FinalizeHandleTable() {
// Finalize the table.
handle_table.Finalize();
m_handle_table.Finalize();
// Note that the table is finalized.
is_handle_table_initialized = false;
m_is_handle_table_initialized = false;
}
void ChangeState(State new_state);
@@ -424,105 +441,107 @@ private:
Result AllocateMainThreadStack(std::size_t stack_size);
/// Memory manager for this process
KPageTable page_table;
KPageTable m_page_table;
/// Current status of the process
State state{};
State m_state{};
/// The ID of this process
u64 process_id = 0;
u64 m_process_id = 0;
/// Title ID corresponding to the process
u64 program_id = 0;
u64 m_program_id = 0;
/// Specifies additional memory to be reserved for the process's memory management by the
/// system. When this is non-zero, secure memory is allocated and used for page table allocation
/// instead of using the normal global page tables/memory block management.
u32 system_resource_size = 0;
u32 m_system_resource_size = 0;
/// Resource limit descriptor for this process
KResourceLimit* resource_limit{};
KResourceLimit* m_resource_limit{};
VAddr system_resource_address{};
KVirtualAddress m_system_resource_address{};
/// The ideal CPU core for this process, threads are scheduled on this core by default.
u8 ideal_core = 0;
u8 m_ideal_core = 0;
/// Contains the parsed process capability descriptors.
ProcessCapabilities capabilities;
ProcessCapabilities m_capabilities;
/// Whether or not this process is AArch64, or AArch32.
/// By default, we currently assume this is true, unless otherwise
/// specified by metadata provided to the process during loading.
bool is_64bit_process = true;
bool m_is_64bit_process = true;
/// Total running time for the process in ticks.
std::atomic<u64> total_process_running_time_ticks = 0;
std::atomic<u64> m_total_process_running_time_ticks = 0;
/// Per-process handle table for storing created object handles in.
KHandleTable handle_table;
KHandleTable m_handle_table;
/// Per-process address arbiter.
KAddressArbiter address_arbiter;
KAddressArbiter m_address_arbiter;
/// The per-process mutex lock instance used for handling various
/// forms of services, such as lock arbitration, and condition
/// variable related facilities.
KConditionVariable condition_var;
KConditionVariable m_condition_var;
/// Address indicating the location of the process' dedicated TLS region.
VAddr plr_address = 0;
KProcessAddress m_plr_address = 0;
/// Random values for svcGetInfo RandomEntropy
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
std::array<u64, RANDOM_ENTROPY_SIZE> m_random_entropy{};
/// List of threads that are running with this process as their owner.
std::list<KThread*> thread_list;
std::list<KThread*> m_thread_list;
/// List of shared memory that are running with this process as their owner.
std::list<KSharedMemoryInfo*> shared_memory_list;
std::list<KSharedMemoryInfo*> m_shared_memory_list;
/// Address of the top of the main thread's stack
VAddr main_thread_stack_top{};
KProcessAddress m_main_thread_stack_top{};
/// Size of the main thread's stack
std::size_t main_thread_stack_size{};
std::size_t m_main_thread_stack_size{};
/// Memory usage capacity for the process
std::size_t memory_usage_capacity{};
std::size_t m_memory_usage_capacity{};
/// Process total image size
std::size_t image_size{};
std::size_t m_image_size{};
/// Schedule count of this process
s64 schedule_count{};
s64 m_schedule_count{};
size_t memory_release_hint{};
size_t m_memory_release_hint{};
bool is_signaled{};
bool is_suspended{};
bool is_immortal{};
bool is_handle_table_initialized{};
bool is_initialized{};
std::string name{};
std::atomic<u16> num_running_threads{};
bool m_is_signaled{};
bool m_is_suspended{};
bool m_is_immortal{};
bool m_is_handle_table_initialized{};
bool m_is_initialized{};
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{};
std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{};
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{};
std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> watchpoints{};
std::map<VAddr, u64> debug_page_refcounts;
std::atomic<u16> m_num_running_threads{};
KThread* exception_thread{};
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{};
std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{};
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_pinned_threads{};
std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> m_watchpoints{};
std::map<KProcessAddress, u64> m_debug_page_refcounts;
KLightLock state_lock;
KLightLock list_lock;
KThread* m_exception_thread{};
KLightLock m_state_lock;
KLightLock m_list_lock;
using TLPTree =
Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
using TLPIterator = TLPTree::iterator;
TLPTree fully_used_tlp_tree;
TLPTree partially_used_tlp_tree;
TLPTree m_fully_used_tlp_tree;
TLPTree m_partially_used_tlp_tree;
};
} // namespace Kernel

View File

@@ -11,7 +11,7 @@
namespace Kernel {
KReadableEvent::KReadableEvent(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KReadableEvent::KReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KReadableEvent::~KReadableEvent() = default;
@@ -25,7 +25,7 @@ void KReadableEvent::Initialize(KEvent* parent) {
}
bool KReadableEvent::IsSignaled() const {
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
return m_is_signaled;
}
@@ -33,7 +33,7 @@ bool KReadableEvent::IsSignaled() const {
void KReadableEvent::Destroy() {
if (m_parent) {
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
m_parent->OnReadableEventDestroyed();
}
m_parent->Close();
@@ -41,31 +41,29 @@ void KReadableEvent::Destroy() {
}
Result KReadableEvent::Signal() {
KScopedSchedulerLock lk{kernel};
KScopedSchedulerLock lk{m_kernel};
if (!m_is_signaled) {
m_is_signaled = true;
this->NotifyAvailable();
}
return ResultSuccess;
R_SUCCEED();
}
Result KReadableEvent::Clear() {
this->Reset();
return ResultSuccess;
R_SUCCEED();
}
Result KReadableEvent::Reset() {
KScopedSchedulerLock lk{kernel};
KScopedSchedulerLock lk{m_kernel};
if (!m_is_signaled) {
return ResultInvalidState;
}
R_UNLESS(m_is_signaled, ResultInvalidState);
m_is_signaled = false;
return ResultSuccess;
R_SUCCEED();
}
} // namespace Kernel

View File

@@ -17,7 +17,7 @@ class KReadableEvent : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KReadableEvent, KSynchronizationObject);
public:
explicit KReadableEvent(KernelCore& kernel_);
explicit KReadableEvent(KernelCore& kernel);
~KReadableEvent() override;
void Initialize(KEvent* parent);

View File

@@ -11,12 +11,12 @@
namespace Kernel {
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
KResourceLimit::KResourceLimit(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, lock{kernel_}, cond_var{kernel_} {}
KResourceLimit::KResourceLimit(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{m_kernel}, m_cond_var{m_kernel} {}
KResourceLimit::~KResourceLimit() = default;
void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) {
core_timing = core_timing_;
void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing) {
m_core_timing = core_timing;
}
void KResourceLimit::Finalize() {}
@@ -25,11 +25,11 @@ s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
KScopedLightLock lk{lock};
value = limit_values[index];
KScopedLightLock lk{m_lock};
value = m_limit_values[index];
ASSERT(value >= 0);
ASSERT(current_values[index] <= limit_values[index]);
ASSERT(current_hints[index] <= current_values[index]);
ASSERT(m_current_values[index] <= m_limit_values[index]);
ASSERT(m_current_hints[index] <= m_current_values[index]);
}
return value;
}
@@ -38,11 +38,11 @@ s64 KResourceLimit::GetCurrentValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
KScopedLightLock lk{lock};
value = current_values[index];
KScopedLightLock lk{m_lock};
value = m_current_values[index];
ASSERT(value >= 0);
ASSERT(current_values[index] <= limit_values[index]);
ASSERT(current_hints[index] <= current_values[index]);
ASSERT(m_current_values[index] <= m_limit_values[index]);
ASSERT(m_current_hints[index] <= m_current_values[index]);
}
return value;
}
@@ -51,11 +51,11 @@ s64 KResourceLimit::GetPeakValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
KScopedLightLock lk{lock};
value = peak_values[index];
KScopedLightLock lk{m_lock};
value = m_peak_values[index];
ASSERT(value >= 0);
ASSERT(current_values[index] <= limit_values[index]);
ASSERT(current_hints[index] <= current_values[index]);
ASSERT(m_current_values[index] <= m_limit_values[index]);
ASSERT(m_current_hints[index] <= m_current_values[index]);
}
return value;
}
@@ -64,11 +64,11 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
KScopedLightLock lk(lock);
ASSERT(current_values[index] >= 0);
ASSERT(current_values[index] <= limit_values[index]);
ASSERT(current_hints[index] <= current_values[index]);
value = limit_values[index] - current_values[index];
KScopedLightLock lk(m_lock);
ASSERT(m_current_values[index] >= 0);
ASSERT(m_current_values[index] <= m_limit_values[index]);
ASSERT(m_current_hints[index] <= m_current_values[index]);
value = m_limit_values[index] - m_current_values[index];
}
return value;
@@ -76,51 +76,51 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
Result KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
const auto index = static_cast<std::size_t>(which);
KScopedLightLock lk(lock);
R_UNLESS(current_values[index] <= value, ResultInvalidState);
KScopedLightLock lk(m_lock);
R_UNLESS(m_current_values[index] <= value, ResultInvalidState);
limit_values[index] = value;
peak_values[index] = current_values[index];
m_limit_values[index] = value;
m_peak_values[index] = m_current_values[index];
return ResultSuccess;
R_SUCCEED();
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
return Reserve(which, value, m_core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
ASSERT(value >= 0);
const auto index = static_cast<std::size_t>(which);
KScopedLightLock lk(lock);
KScopedLightLock lk(m_lock);
ASSERT(current_hints[index] <= current_values[index]);
if (current_hints[index] >= limit_values[index]) {
ASSERT(m_current_hints[index] <= m_current_values[index]);
if (m_current_hints[index] >= m_limit_values[index]) {
return false;
}
// Loop until we reserve or run out of time.
while (true) {
ASSERT(current_values[index] <= limit_values[index]);
ASSERT(current_hints[index] <= current_values[index]);
ASSERT(m_current_values[index] <= m_limit_values[index]);
ASSERT(m_current_hints[index] <= m_current_values[index]);
// If we would overflow, don't allow to succeed.
if (Common::WrappingAdd(current_values[index], value) <= current_values[index]) {
if (Common::WrappingAdd(m_current_values[index], value) <= m_current_values[index]) {
break;
}
if (current_values[index] + value <= limit_values[index]) {
current_values[index] += value;
current_hints[index] += value;
peak_values[index] = std::max(peak_values[index], current_values[index]);
if (m_current_values[index] + value <= m_limit_values[index]) {
m_current_values[index] += value;
m_current_hints[index] += value;
m_peak_values[index] = std::max(m_peak_values[index], m_current_values[index]);
return true;
}
if (current_hints[index] + value <= limit_values[index] &&
(timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
waiter_count++;
cond_var.Wait(&lock, timeout, false);
waiter_count--;
if (m_current_hints[index] + value <= m_limit_values[index] &&
(timeout < 0 || m_core_timing->GetGlobalTimeNs().count() < timeout)) {
m_waiter_count++;
m_cond_var.Wait(std::addressof(m_lock), timeout, false);
m_waiter_count--;
} else {
break;
}
@@ -138,23 +138,23 @@ void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
ASSERT(hint >= 0);
const auto index = static_cast<std::size_t>(which);
KScopedLightLock lk(lock);
ASSERT(current_values[index] <= limit_values[index]);
ASSERT(current_hints[index] <= current_values[index]);
ASSERT(value <= current_values[index]);
ASSERT(hint <= current_hints[index]);
KScopedLightLock lk(m_lock);
ASSERT(m_current_values[index] <= m_limit_values[index]);
ASSERT(m_current_hints[index] <= m_current_values[index]);
ASSERT(value <= m_current_values[index]);
ASSERT(hint <= m_current_hints[index]);
current_values[index] -= value;
current_hints[index] -= hint;
m_current_values[index] -= value;
m_current_hints[index] -= hint;
if (waiter_count != 0) {
cond_var.Broadcast();
if (m_waiter_count != 0) {
m_cond_var.Broadcast();
}
}
KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) {
auto* resource_limit = KResourceLimit::Create(system.Kernel());
resource_limit->Initialize(&system.CoreTiming());
resource_limit->Initialize(std::addressof(system.CoreTiming()));
// Initialize default resource limit values.
// TODO(bunnei): These values are the system defaults, the limits for service processes are

View File

@@ -28,10 +28,10 @@ class KResourceLimit final
KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject);
public:
explicit KResourceLimit(KernelCore& kernel_);
explicit KResourceLimit(KernelCore& kernel);
~KResourceLimit() override;
void Initialize(const Core::Timing::CoreTiming* core_timing_);
void Initialize(const Core::Timing::CoreTiming* core_timing);
void Finalize() override;
s64 GetLimitValue(LimitableResource which) const;
@@ -46,18 +46,18 @@ public:
void Release(LimitableResource which, s64 value);
void Release(LimitableResource which, s64 value, s64 hint);
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
static void PostDestroy(uintptr_t arg) {}
private:
using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
ResourceArray limit_values{};
ResourceArray current_values{};
ResourceArray current_hints{};
ResourceArray peak_values{};
mutable KLightLock lock;
s32 waiter_count{};
KLightConditionVariable cond_var;
const Core::Timing::CoreTiming* core_timing{};
ResourceArray m_limit_values{};
ResourceArray m_current_values{};
ResourceArray m_current_hints{};
ResourceArray m_peak_values{};
mutable KLightLock m_lock;
s32 m_waiter_count{};
KLightConditionVariable m_cond_var;
const Core::Timing::CoreTiming* m_core_timing{};
};
KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size);

View File

@@ -27,7 +27,7 @@ static void IncrementScheduledCount(Kernel::KThread* thread) {
}
}
KScheduler::KScheduler(KernelCore& kernel_) : kernel{kernel_} {
KScheduler::KScheduler(KernelCore& kernel) : m_kernel{kernel} {
m_switch_fiber = std::make_shared<Common::Fiber>([this] {
while (true) {
ScheduleImplFiber();
@@ -47,7 +47,7 @@ void KScheduler::SetInterruptTaskRunnable() {
void KScheduler::RequestScheduleOnInterrupt() {
m_state.needs_scheduling = true;
if (CanSchedule(kernel)) {
if (CanSchedule(m_kernel)) {
ScheduleOnInterrupt();
}
}
@@ -97,50 +97,50 @@ u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
}
void KScheduler::Schedule() {
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
ASSERT(m_core_id == GetCurrentCoreId(kernel));
ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
ASSERT(m_core_id == GetCurrentCoreId(m_kernel));
ScheduleImpl();
}
void KScheduler::ScheduleOnInterrupt() {
GetCurrentThread(kernel).DisableDispatch();
GetCurrentThread(m_kernel).DisableDispatch();
Schedule();
GetCurrentThread(kernel).EnableDispatch();
GetCurrentThread(m_kernel).EnableDispatch();
}
void KScheduler::PreemptSingleCore() {
GetCurrentThread(kernel).DisableDispatch();
GetCurrentThread(m_kernel).DisableDispatch();
auto* thread = GetCurrentThreadPointer(kernel);
auto& previous_scheduler = kernel.Scheduler(thread->GetCurrentCore());
auto* thread = GetCurrentThreadPointer(m_kernel);
auto& previous_scheduler = m_kernel.Scheduler(thread->GetCurrentCore());
previous_scheduler.Unload(thread);
Common::Fiber::YieldTo(thread->GetHostContext(), *m_switch_fiber);
GetCurrentThread(kernel).EnableDispatch();
GetCurrentThread(m_kernel).EnableDispatch();
}
void KScheduler::RescheduleCurrentCore() {
ASSERT(!kernel.IsPhantomModeForSingleCore());
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
ASSERT(!m_kernel.IsPhantomModeForSingleCore());
ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
GetCurrentThread(kernel).EnableDispatch();
GetCurrentThread(m_kernel).EnableDispatch();
if (m_state.needs_scheduling.load()) {
// Disable interrupts, and then check again if rescheduling is needed.
// KScopedInterruptDisable intr_disable;
kernel.CurrentScheduler()->RescheduleCurrentCoreImpl();
m_kernel.CurrentScheduler()->RescheduleCurrentCoreImpl();
}
}
void KScheduler::RescheduleCurrentCoreImpl() {
// Check that scheduling is needed.
if (m_state.needs_scheduling.load()) [[likely]] {
GetCurrentThread(kernel).DisableDispatch();
GetCurrentThread(m_kernel).DisableDispatch();
Schedule();
GetCurrentThread(kernel).EnableDispatch();
GetCurrentThread(m_kernel).EnableDispatch();
}
}
@@ -149,18 +149,18 @@ void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core
m_core_id = core_id;
m_idle_thread = idle_thread;
// m_state.idle_thread_stack = m_idle_thread->GetStackTop();
// m_state.interrupt_task_manager = &kernel.GetInterruptTaskManager();
// m_state.interrupt_task_manager = std::addressof(kernel.GetInterruptTaskManager());
// Insert the main thread into the priority queue.
// {
// KScopedSchedulerLock lk{kernel};
// GetPriorityQueue(kernel).PushBack(GetCurrentThreadPointer(kernel));
// SetSchedulerUpdateNeeded(kernel);
// KScopedSchedulerLock lk{m_kernel};
// GetPriorityQueue(m_kernel).PushBack(GetCurrentThreadPointer(m_kernel));
// SetSchedulerUpdateNeeded(m_kernel);
// }
// Bind interrupt handler.
// kernel.GetInterruptManager().BindHandler(
// GetSchedulerInterruptHandler(kernel), KInterruptName::Scheduler, m_core_id,
// GetSchedulerInterruptHandler(m_kernel), KInterruptName::Scheduler, m_core_id,
// KInterruptController::PriorityLevel::Scheduler, false, false);
// Set the current thread.
@@ -168,7 +168,7 @@ void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core
}
void KScheduler::Activate() {
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
// m_state.should_count_idle = KTargetSystem::IsDebugMode();
m_is_active = true;
@@ -176,7 +176,7 @@ void KScheduler::Activate() {
}
void KScheduler::OnThreadStart() {
GetCurrentThread(kernel).EnableDispatch();
GetCurrentThread(m_kernel).EnableDispatch();
}
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
@@ -184,7 +184,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
prev_highest_thread != highest_thread) [[likely]] {
if (prev_highest_thread != nullptr) [[likely]] {
IncrementScheduledCount(prev_highest_thread);
prev_highest_thread->SetLastScheduledTick(kernel.System().CoreTiming().GetCPUTicks());
prev_highest_thread->SetLastScheduledTick(m_kernel.System().CoreTiming().GetCPUTicks());
}
if (m_state.should_count_idle) {
if (highest_thread != nullptr) [[likely]] {
@@ -328,8 +328,8 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
}
void KScheduler::SwitchThread(KThread* next_thread) {
KProcess* const cur_process = GetCurrentProcessPointer(kernel);
KThread* const cur_thread = GetCurrentThreadPointer(kernel);
KProcess* const cur_process = GetCurrentProcessPointer(m_kernel);
KThread* const cur_thread = GetCurrentThreadPointer(m_kernel);
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
if (next_thread == nullptr) {
@@ -351,7 +351,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
// Update the CPU time tracking variables.
const s64 prev_tick = m_last_context_switch_time;
const s64 cur_tick = kernel.System().CoreTiming().GetCPUTicks();
const s64 cur_tick = m_kernel.System().CoreTiming().GetCPUTicks();
const s64 tick_diff = cur_tick - prev_tick;
cur_thread->AddCpuTime(m_core_id, tick_diff);
if (cur_process != nullptr) {
@@ -375,7 +375,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
// }
// Set the new thread.
SetCurrentThread(kernel, next_thread);
SetCurrentThread(m_kernel, next_thread);
m_current_thread = next_thread;
// Set the new Thread Local region.
@@ -388,7 +388,7 @@ void KScheduler::ScheduleImpl() {
std::atomic_thread_fence(std::memory_order_seq_cst);
// Load the appropriate thread pointers for scheduling.
KThread* const cur_thread{GetCurrentThreadPointer(kernel)};
KThread* const cur_thread{GetCurrentThreadPointer(m_kernel)};
KThread* highest_priority_thread{m_state.highest_priority_thread};
// Check whether there are runnable interrupt tasks.
@@ -411,7 +411,7 @@ void KScheduler::ScheduleImpl() {
m_switch_cur_thread = cur_thread;
m_switch_highest_priority_thread = highest_priority_thread;
m_switch_from_schedule = true;
Common::Fiber::YieldTo(cur_thread->host_context, *m_switch_fiber);
Common::Fiber::YieldTo(cur_thread->m_host_context, *m_switch_fiber);
// Returning from ScheduleImpl occurs after this thread has been scheduled again.
}
@@ -450,7 +450,7 @@ void KScheduler::ScheduleImplFiber() {
// We want to try to lock the highest priority thread's context.
// Try to take it.
while (!highest_priority_thread->context_guard.try_lock()) {
while (!highest_priority_thread->m_context_guard.try_lock()) {
// The highest priority thread's context is already locked.
// Check if we need scheduling. If we don't, we can retry directly.
if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) {
@@ -468,7 +468,7 @@ void KScheduler::ScheduleImplFiber() {
if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) {
// Our switch failed.
// We should unlock the thread context, and then retry.
highest_priority_thread->context_guard.unlock();
highest_priority_thread->m_context_guard.unlock();
goto retry;
} else {
break;
@@ -489,30 +489,30 @@ void KScheduler::ScheduleImplFiber() {
Reload(highest_priority_thread);
// Reload the host thread.
Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->host_context);
Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->m_host_context);
}
void KScheduler::Unload(KThread* thread) {
auto& cpu_core = kernel.System().ArmInterface(m_core_id);
auto& cpu_core = m_kernel.System().ArmInterface(m_core_id);
cpu_core.SaveContext(thread->GetContext32());
cpu_core.SaveContext(thread->GetContext64());
// Save the TPIDR_EL0 system register in case it was modified.
thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
thread->SetTpidrEl0(cpu_core.GetTPIDR_EL0());
cpu_core.ClearExclusiveState();
// Check if the thread is terminated by checking the DPC flags.
if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
// The thread isn't terminated, so we want to unlock it.
thread->context_guard.unlock();
thread->m_context_guard.unlock();
}
}
void KScheduler::Reload(KThread* thread) {
auto& cpu_core = kernel.System().ArmInterface(m_core_id);
auto& cpu_core = m_kernel.System().ArmInterface(m_core_id);
cpu_core.LoadContext(thread->GetContext32());
cpu_core.LoadContext(thread->GetContext64());
cpu_core.SetTlsAddress(thread->GetTLSAddress());
cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
cpu_core.SetTlsAddress(GetInteger(thread->GetTlsAddress()));
cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0());
cpu_core.LoadWatchpointArray(thread->GetOwnerProcess()->GetWatchpoints());
cpu_core.ClearExclusiveState();
}
@@ -891,7 +891,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) {
if (const u64 core_mask = cores_needing_scheduling & ~(1ULL << m_core_id); core_mask != 0) {
RescheduleCores(kernel, core_mask);
RescheduleCores(m_kernel, core_mask);
}
}

View File

@@ -80,17 +80,17 @@ public:
return GetCurrentThread(kernel).GetDisableDispatchCount() == 0;
}
static bool IsSchedulerLockedByCurrentThread(KernelCore& kernel) {
return kernel.GlobalSchedulerContext().scheduler_lock.IsLockedByCurrentThread();
return kernel.GlobalSchedulerContext().m_scheduler_lock.IsLockedByCurrentThread();
}
static bool IsSchedulerUpdateNeeded(KernelCore& kernel) {
return kernel.GlobalSchedulerContext().scheduler_update_needed;
return kernel.GlobalSchedulerContext().m_scheduler_update_needed;
}
static void SetSchedulerUpdateNeeded(KernelCore& kernel) {
kernel.GlobalSchedulerContext().scheduler_update_needed = true;
kernel.GlobalSchedulerContext().m_scheduler_update_needed = true;
}
static void ClearSchedulerUpdateNeeded(KernelCore& kernel) {
kernel.GlobalSchedulerContext().scheduler_update_needed = false;
kernel.GlobalSchedulerContext().m_scheduler_update_needed = false;
}
static void DisableScheduling(KernelCore& kernel);
@@ -115,7 +115,7 @@ public:
private:
// Static private API.
static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel) {
return kernel.GlobalSchedulerContext().priority_queue;
return kernel.GlobalSchedulerContext().m_priority_queue;
}
static u64 UpdateHighestPriorityThreadsImpl(KernelCore& kernel);
@@ -149,7 +149,7 @@ private:
KInterruptTaskManager* interrupt_task_manager{nullptr};
};
KernelCore& kernel;
KernelCore& m_kernel;
SchedulingState m_state;
bool m_is_active{false};
s32 m_core_id{0};
@@ -166,7 +166,7 @@ private:
class KScopedSchedulerLock : public KScopedLock<KScheduler::LockType> {
public:
explicit KScopedSchedulerLock(KernelCore& kernel)
: KScopedLock(kernel.GlobalSchedulerContext().scheduler_lock) {}
: KScopedLock(kernel.GlobalSchedulerContext().m_scheduler_lock) {}
~KScopedSchedulerLock() = default;
};

View File

@@ -14,74 +14,67 @@
namespace Kernel {
class KernelCore;
class GlobalSchedulerContext;
template <typename SchedulerType>
class KAbstractSchedulerLock {
public:
explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {}
explicit KAbstractSchedulerLock(KernelCore& kernel) : m_kernel{kernel} {}
bool IsLockedByCurrentThread() const {
return owner_thread == GetCurrentThreadPointer(kernel);
return m_owner_thread == GetCurrentThreadPointer(m_kernel);
}
void Lock() {
// If we are shutting down the kernel, none of this is relevant anymore.
if (kernel.IsShuttingDown()) {
return;
}
if (IsLockedByCurrentThread()) {
if (this->IsLockedByCurrentThread()) {
// If we already own the lock, the lock count should be > 0.
// For debug, ensure this is true.
ASSERT(lock_count > 0);
ASSERT(m_lock_count > 0);
} else {
// Otherwise, we want to disable scheduling and acquire the spinlock.
SchedulerType::DisableScheduling(kernel);
spin_lock.Lock();
SchedulerType::DisableScheduling(m_kernel);
m_spin_lock.Lock();
ASSERT(lock_count == 0);
ASSERT(owner_thread == nullptr);
ASSERT(m_lock_count == 0);
ASSERT(m_owner_thread == nullptr);
// Take ownership of the lock.
owner_thread = GetCurrentThreadPointer(kernel);
m_owner_thread = GetCurrentThreadPointer(m_kernel);
}
// Increment the lock count.
lock_count++;
m_lock_count++;
}
void Unlock() {
// If we are shutting down the kernel, none of this is relevant anymore.
if (kernel.IsShuttingDown()) {
return;
}
ASSERT(IsLockedByCurrentThread());
ASSERT(lock_count > 0);
ASSERT(this->IsLockedByCurrentThread());
ASSERT(m_lock_count > 0);
// Release an instance of the lock.
if ((--lock_count) == 0) {
if ((--m_lock_count) == 0) {
// Perform a memory barrier here.
std::atomic_thread_fence(std::memory_order_seq_cst);
// We're no longer going to hold the lock. Take note of what cores need scheduling.
const u64 cores_needing_scheduling =
SchedulerType::UpdateHighestPriorityThreads(kernel);
SchedulerType::UpdateHighestPriorityThreads(m_kernel);
// Note that we no longer hold the lock, and unlock the spinlock.
owner_thread = nullptr;
spin_lock.Unlock();
m_owner_thread = nullptr;
m_spin_lock.Unlock();
// Enable scheduling, and perform a rescheduling operation.
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
SchedulerType::EnableScheduling(m_kernel, cores_needing_scheduling);
}
}
private:
KernelCore& kernel;
KAlignedSpinLock spin_lock{};
s32 lock_count{};
std::atomic<KThread*> owner_thread{};
friend class GlobalSchedulerContext;
KernelCore& m_kernel;
KAlignedSpinLock m_spin_lock{};
s32 m_lock_count{};
std::atomic<KThread*> m_owner_thread{};
};
} // namespace Kernel

View File

@@ -18,15 +18,15 @@ std::is_reference_v<T>&& requires(T& t) {
template <typename T>
requires KLockable<T>
class [[nodiscard]] KScopedLock {
class KScopedLock {
public:
explicit KScopedLock(T* l) : lock_ptr(l) {
this->lock_ptr->Lock();
explicit KScopedLock(T* l) : m_lock(*l) {}
explicit KScopedLock(T& l) : m_lock(l) {
m_lock.Lock();
}
explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) {}
~KScopedLock() {
this->lock_ptr->Unlock();
m_lock.Unlock();
}
KScopedLock(const KScopedLock&) = delete;
@@ -36,7 +36,7 @@ public:
KScopedLock& operator=(KScopedLock&&) = delete;
private:
T* lock_ptr;
T& m_lock;
};
} // namespace Kernel

View File

@@ -12,20 +12,20 @@ namespace Kernel {
class KScopedResourceReservation {
public:
explicit KScopedResourceReservation(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);
: m_limit(l), m_value(v), m_resource(r) {
if (m_limit && m_value) {
m_succeeded = m_limit->Reserve(m_resource, m_value, timeout);
} else {
success = true;
m_succeeded = true;
}
}
explicit KScopedResourceReservation(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);
: m_limit(l), m_value(v), m_resource(r) {
if (m_limit && m_value) {
m_succeeded = m_limit->Reserve(m_resource, m_value);
} else {
success = true;
m_succeeded = true;
}
}
@@ -36,26 +36,26 @@ public:
: KScopedResourceReservation(p->GetResourceLimit(), r, v) {}
~KScopedResourceReservation() noexcept {
if (resource_limit && value && success) {
// resource was not committed, release the reservation.
resource_limit->Release(resource, value);
if (m_limit && m_value && m_succeeded) {
// Resource was not committed, release the reservation.
m_limit->Release(m_resource, m_value);
}
}
/// Commit the resource reservation, destruction of this object does not release the resource
void Commit() {
resource_limit = nullptr;
m_limit = nullptr;
}
[[nodiscard]] bool Succeeded() const {
return success;
bool Succeeded() const {
return m_succeeded;
}
private:
KResourceLimit* resource_limit{};
s64 value;
LimitableResource resource;
bool success;
KResourceLimit* m_limit{};
s64 m_value{};
LimitableResource m_resource{};
bool m_succeeded{};
};
} // namespace Kernel

View File

@@ -11,39 +11,39 @@
namespace Kernel {
class [[nodiscard]] KScopedSchedulerLockAndSleep {
class KScopedSchedulerLockAndSleep {
public:
explicit KScopedSchedulerLockAndSleep(KernelCore& kernel_, KHardwareTimer** out_timer,
KThread* t, s64 timeout)
: kernel(kernel_), timeout_tick(timeout), thread(t), timer() {
explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KHardwareTimer** out_timer,
KThread* thread, s64 timeout_tick)
: m_kernel(kernel), m_timeout_tick(timeout_tick), m_thread(thread), m_timer() {
// Lock the scheduler.
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
kernel.GlobalSchedulerContext().m_scheduler_lock.Lock();
// Set our timer only if the time is positive.
timer = (timeout_tick > 0) ? std::addressof(kernel.HardwareTimer()) : nullptr;
m_timer = (timeout_tick > 0) ? std::addressof(kernel.HardwareTimer()) : nullptr;
*out_timer = timer;
*out_timer = m_timer;
}
~KScopedSchedulerLockAndSleep() {
// Register the sleep.
if (timeout_tick > 0) {
timer->RegisterTask(thread, timeout_tick);
if (m_timeout_tick > 0) {
m_timer->RegisterTask(m_thread, m_timeout_tick);
}
// Unlock the scheduler.
kernel.GlobalSchedulerContext().scheduler_lock.Unlock();
m_kernel.GlobalSchedulerContext().m_scheduler_lock.Unlock();
}
void CancelSleep() {
timeout_tick = 0;
m_timeout_tick = 0;
}
private:
KernelCore& kernel;
s64 timeout_tick{};
KThread* thread{};
KHardwareTimer* timer{};
KernelCore& m_kernel;
s64 m_timeout_tick{};
KThread* m_thread{};
KHardwareTimer* m_timer{};
};
} // namespace Kernel

View File

@@ -12,13 +12,12 @@
namespace Kernel {
KServerPort::KServerPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KServerPort::~KServerPort() = default;
void KServerPort::Initialize(KPort* parent_port_, std::string&& name_) {
void KServerPort::Initialize(KPort* parent) {
// Set member variables.
parent = parent_port_;
name = std::move(name_);
m_parent = parent;
}
bool KServerPort::IsLight() const {
@@ -36,10 +35,10 @@ void KServerPort::CleanupSessions() {
// Get the last session in the list
KServerSession* session = nullptr;
{
KScopedSchedulerLock sl{kernel};
if (!session_list.empty()) {
session = std::addressof(session_list.front());
session_list.pop_front();
KScopedSchedulerLock sl{m_kernel};
if (!m_session_list.empty()) {
session = std::addressof(m_session_list.front());
m_session_list.pop_front();
}
}
@@ -54,13 +53,13 @@ void KServerPort::CleanupSessions() {
void KServerPort::Destroy() {
// Note with our parent that we're closed.
parent->OnServerClosed();
m_parent->OnServerClosed();
// Perform necessary cleanup of our session lists.
this->CleanupSessions();
// Close our reference to our parent.
parent->Close();
m_parent->Close();
}
bool KServerPort::IsSignaled() const {
@@ -68,18 +67,18 @@ bool KServerPort::IsSignaled() const {
UNIMPLEMENTED();
return false;
} else {
return !session_list.empty();
return !m_session_list.empty();
}
}
void KServerPort::EnqueueSession(KServerSession* session) {
ASSERT(!this->IsLight());
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// Add the session to our queue.
session_list.push_back(*session);
if (session_list.size() == 1) {
m_session_list.push_back(*session);
if (m_session_list.size() == 1) {
this->NotifyAvailable();
}
}
@@ -87,15 +86,15 @@ void KServerPort::EnqueueSession(KServerSession* session) {
KServerSession* KServerPort::AcceptSession() {
ASSERT(!this->IsLight());
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// Return the first session in the list.
if (session_list.empty()) {
if (m_session_list.empty()) {
return nullptr;
}
KServerSession* session = std::addressof(session_list.front());
session_list.pop_front();
KServerSession* session = std::addressof(m_session_list.front());
m_session_list.pop_front();
return session;
}

View File

@@ -22,17 +22,17 @@ class KServerPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject);
public:
explicit KServerPort(KernelCore& kernel_);
explicit KServerPort(KernelCore& kernel);
~KServerPort() override;
void Initialize(KPort* parent_port_, std::string&& name_);
void Initialize(KPort* parent);
void EnqueueSession(KServerSession* pending_session);
void EnqueueSession(KServerSession* session);
KServerSession* AcceptSession();
const KPort* GetParent() const {
return parent;
return m_parent;
}
bool IsLight() const;
@@ -46,8 +46,8 @@ private:
void CleanupSessions();
SessionList session_list;
KPort* parent{};
SessionList m_session_list{};
KPort* m_parent{};
};
} // namespace Kernel

View File

@@ -28,23 +28,17 @@ namespace Kernel {
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
KServerSession::KServerSession(KernelCore& kernel_)
: KSynchronizationObject{kernel_}, m_lock{kernel_} {}
KServerSession::KServerSession(KernelCore& kernel)
: KSynchronizationObject{kernel}, m_lock{m_kernel} {}
KServerSession::~KServerSession() = default;
void KServerSession::Initialize(KSession* parent_session_, std::string&& name_) {
// Set member variables.
parent = parent_session_;
name = std::move(name_);
}
void KServerSession::Destroy() {
parent->OnServerClosed();
m_parent->OnServerClosed();
this->CleanupRequests();
parent->Close();
m_parent->Close();
}
void KServerSession::OnClientClosed() {
@@ -62,7 +56,7 @@ void KServerSession::OnClientClosed() {
// Get the next request.
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (m_current_request != nullptr && m_current_request != prev_request) {
// Set the request, open a reference as we process it.
@@ -121,7 +115,7 @@ void KServerSession::OnClientClosed() {
// // Get the process and page table.
// KProcess *client_process = thread->GetOwnerProcess();
// auto &client_pt = client_process->GetPageTable();
// auto& client_pt = client_process->GetPageTable();
// // Reply to the request.
// ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(),
@@ -141,10 +135,10 @@ void KServerSession::OnClientClosed() {
}
bool KServerSession::IsSignaled() const {
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// If the client is closed, we're always signaled.
if (parent->IsClientClosed()) {
if (m_parent->IsClientClosed()) {
return true;
}
@@ -154,17 +148,17 @@ bool KServerSession::IsSignaled() const {
Result KServerSession::OnRequest(KSessionRequest* request) {
// Create the wait queue.
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
ThreadQueueImplForKServerSessionRequest wait_queue{m_kernel};
{
// Lock the scheduler.
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// Ensure that we can handle new requests.
R_UNLESS(!parent->IsServerClosed(), ResultSessionClosed);
R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed);
// Check that we're not terminating.
R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), ResultTerminationRequested);
// Get whether we're empty.
const bool was_empty = m_request_list.empty();
@@ -182,11 +176,11 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
R_SUCCEED_IF(request->GetEvent() != nullptr);
// This is a synchronous request, so we should wait for our request to complete.
GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
GetCurrentThread(kernel).BeginWait(&wait_queue);
GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue));
}
return GetCurrentThread(kernel).GetWaitResult();
return GetCurrentThread(m_kernel).GetWaitResult();
}
Result KServerSession::SendReply(bool is_hle) {
@@ -196,7 +190,7 @@ Result KServerSession::SendReply(bool is_hle) {
// Get the request.
KSessionRequest* request;
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// Get the current request.
request = m_current_request;
@@ -219,7 +213,7 @@ Result KServerSession::SendReply(bool is_hle) {
KEvent* event = request->GetEvent();
// Check whether we're closed.
const bool closed = (client_thread == nullptr || parent->IsClientClosed());
const bool closed = (client_thread == nullptr || m_parent->IsClientClosed());
Result result = ResultSuccess;
if (!closed) {
@@ -228,11 +222,11 @@ Result KServerSession::SendReply(bool is_hle) {
// HLE servers write directly to a pointer to the thread command buffer. Therefore
// the reply has already been written in this case.
} else {
Core::Memory::Memory& memory{kernel.System().Memory()};
KThread* server_thread{GetCurrentThreadPointer(kernel)};
Core::Memory::Memory& memory{m_kernel.System().Memory()};
KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
auto* dst_msg_buffer = memory.GetPointer(client_message);
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
}
@@ -254,7 +248,7 @@ Result KServerSession::SendReply(bool is_hle) {
if (event != nullptr) {
// // Get the client process/page table.
// KProcess *client_process = client_thread->GetOwnerProcess();
// KPageTable *client_page_table = &client_process->PageTable();
// KPageTable *client_page_table = std::addressof(client_process->PageTable());
// // If we need to, reply with an async error.
// if (R_FAILED(client_result)) {
@@ -270,7 +264,7 @@ Result KServerSession::SendReply(bool is_hle) {
event->Signal();
} else {
// End the client thread's wait.
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (!client_thread->IsTerminationRequested()) {
client_thread->EndWait(client_result);
@@ -278,7 +272,7 @@ Result KServerSession::SendReply(bool is_hle) {
}
}
return result;
R_RETURN(result);
}
Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context,
@@ -291,10 +285,10 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
KThread* client_thread;
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
// Ensure that we can service the request.
R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed);
// Ensure we aren't already servicing a request.
R_UNLESS(m_current_request == nullptr, ResultNotFound);
@@ -303,7 +297,7 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
R_UNLESS(!m_request_list.empty(), ResultNotFound);
// Pop the first request from the list.
request = &m_request_list.front();
request = std::addressof(m_request_list.front());
m_request_list.pop_front();
// Get the thread for the request.
@@ -325,27 +319,27 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
// bool recv_list_broken = false;
// Receive the message.
Core::Memory::Memory& memory{kernel.System().Memory()};
Core::Memory::Memory& memory{m_kernel.System().Memory()};
if (out_context != nullptr) {
// HLE request.
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))};
*out_context =
std::make_shared<Service::HLERequestContext>(kernel, memory, this, client_thread);
std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
(*out_context)->SetSessionRequestManager(manager);
(*out_context)
->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
cmd_buf);
} else {
KThread* server_thread{GetCurrentThreadPointer(kernel)};
KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
auto* src_msg_buffer = memory.GetPointer(client_message);
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
}
// We succeeded.
return ResultSuccess;
R_SUCCEED();
}
void KServerSession::CleanupRequests() {
@@ -356,7 +350,7 @@ void KServerSession::CleanupRequests() {
// Get the next request.
KSessionRequest* request = nullptr;
{
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (m_current_request) {
// Choose the current request if we have one.
@@ -364,7 +358,7 @@ void KServerSession::CleanupRequests() {
m_current_request = nullptr;
} else if (!m_request_list.empty()) {
// Pop the request from the front of the list.
request = &m_request_list.front();
request = std::addressof(m_request_list.front());
m_request_list.pop_front();
}
}
@@ -387,7 +381,8 @@ void KServerSession::CleanupRequests() {
// KProcess *client_process = (client_thread != nullptr) ?
// client_thread->GetOwnerProcess() : nullptr;
// KProcessPageTable *client_page_table = (client_process != nullptr) ?
// &client_process->GetPageTable() : nullptr;
// std::addressof(client_process->GetPageTable())
// : nullptr;
// Cleanup the mappings.
// Result result = CleanupMap(request, server_process, client_page_table);
@@ -407,7 +402,7 @@ void KServerSession::CleanupRequests() {
event->Signal();
} else {
// End the client thread's wait.
KScopedSchedulerLock sl{kernel};
KScopedSchedulerLock sl{m_kernel};
if (!client_thread->IsTerminationRequested()) {
client_thread->EndWait(ResultSessionClosed);

View File

@@ -33,19 +33,17 @@ class KServerSession final : public KSynchronizationObject,
friend class ServiceThread;
public:
explicit KServerSession(KernelCore& kernel_);
explicit KServerSession(KernelCore& kernel);
~KServerSession() override;
void Destroy() override;
void Initialize(KSession* parent_session_, std::string&& name_);
KSession* GetParent() {
return parent;
void Initialize(KSession* p) {
m_parent = p;
}
const KSession* GetParent() const {
return parent;
return m_parent;
}
bool IsSignaled() const override;
@@ -66,10 +64,10 @@ private:
void CleanupRequests();
/// KSession that owns this KServerSession
KSession* parent{};
KSession* m_parent{};
/// List of threads which are pending a reply.
boost::intrusive::list<KSessionRequest> m_request_list;
boost::intrusive::list<KSessionRequest> m_request_list{};
KSessionRequest* m_current_request{};
KLightLock m_lock;

View File

@@ -9,69 +9,63 @@
namespace Kernel {
KSession::KSession(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
KSession::KSession(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_server{kernel}, m_client{kernel} {}
KSession::~KSession() = default;
void KSession::Initialize(KClientPort* port_, const std::string& name_) {
void KSession::Initialize(KClientPort* client_port, uintptr_t name) {
// Increment reference count.
// Because reference count is one on creation, this will result
// in a reference count of two. Thus, when both server and client are closed
// this object will be destroyed.
Open();
this->Open();
// Create our sub sessions.
KAutoObject::Create(std::addressof(server));
KAutoObject::Create(std::addressof(client));
KAutoObject::Create(std::addressof(m_server));
KAutoObject::Create(std::addressof(m_client));
// Initialize our sub sessions.
server.Initialize(this, name_ + ":Server");
client.Initialize(this, name_ + ":Client");
m_server.Initialize(this);
m_client.Initialize(this);
// Set state and name.
SetState(State::Normal);
name = name_;
this->SetState(State::Normal);
m_name = name;
// Set our owner process.
//! FIXME: this is the wrong process!
process = kernel.ApplicationProcess();
process->Open();
m_process = m_kernel.ApplicationProcess();
m_process->Open();
// Set our port.
port = port_;
if (port != nullptr) {
port->Open();
m_port = client_port;
if (m_port != nullptr) {
m_port->Open();
}
// Mark initialized.
initialized = true;
m_initialized = true;
}
void KSession::Finalize() {
if (port == nullptr) {
return;
if (m_port != nullptr) {
m_port->OnSessionFinalized();
m_port->Close();
}
port->OnSessionFinalized();
port->Close();
}
void KSession::OnServerClosed() {
if (GetState() != State::Normal) {
return;
if (this->GetState() == State::Normal) {
this->SetState(State::ServerClosed);
m_client.OnServerClosed();
}
SetState(State::ServerClosed);
client.OnServerClosed();
}
void KSession::OnClientClosed() {
if (GetState() != State::Normal) {
return;
if (this->GetState() == State::Normal) {
SetState(State::ClientClosed);
m_server.OnClientClosed();
}
SetState(State::ClientClosed);
server.OnClientClosed();
}
void KSession::PostDestroy(uintptr_t arg) {

View File

@@ -18,19 +18,18 @@ class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAut
KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
public:
explicit KSession(KernelCore& kernel_);
explicit KSession(KernelCore& kernel);
~KSession() override;
void Initialize(KClientPort* port_, const std::string& name_);
void Initialize(KClientPort* port, uintptr_t name);
void Finalize() override;
bool IsInitialized() const override {
return initialized;
return m_initialized;
}
uintptr_t GetPostDestroyArgument() const override {
return reinterpret_cast<uintptr_t>(process);
return reinterpret_cast<uintptr_t>(m_process);
}
static void PostDestroy(uintptr_t arg);
@@ -48,27 +47,23 @@ public:
}
KClientSession& GetClientSession() {
return client;
return m_client;
}
KServerSession& GetServerSession() {
return server;
return m_server;
}
const KClientSession& GetClientSession() const {
return client;
return m_client;
}
const KServerSession& GetServerSession() const {
return server;
return m_server;
}
const KClientPort* GetParent() const {
return port;
}
KClientPort* GetParent() {
return port;
return m_port;
}
private:
@@ -80,20 +75,20 @@ private:
};
void SetState(State state) {
atomic_state = static_cast<u8>(state);
m_atomic_state = static_cast<u8>(state);
}
State GetState() const {
return static_cast<State>(atomic_state.load(std::memory_order_relaxed));
return static_cast<State>(m_atomic_state.load());
}
KServerSession server;
KClientSession client;
std::atomic<std::underlying_type_t<State>> atomic_state{
static_cast<std::underlying_type_t<State>>(State::Invalid)};
KClientPort* port{};
KProcess* process{};
bool initialized{};
KServerSession m_server;
KClientSession m_client;
KClientPort* m_port{};
uintptr_t m_name{};
KProcess* m_process{};
std::atomic<u8> m_atomic_state{static_cast<u8>(State::Invalid)};
bool m_initialized{};
};
} // namespace Kernel

View File

@@ -6,54 +6,55 @@
namespace Kernel {
Result KSessionRequest::SessionMappings::PushMap(VAddr client, VAddr server, size_t size,
KMemoryState state, size_t index) {
Result KSessionRequest::SessionMappings::PushMap(KProcessAddress client, KProcessAddress server,
size_t size, KMemoryState state, size_t index) {
// At most 15 buffers of each type (4-bit descriptor counts).
ASSERT(index < ((1ul << 4) - 1) * 3);
// Get the mapping.
Mapping* mapping;
if (index < NumStaticMappings) {
mapping = &m_static_mappings[index];
mapping = std::addressof(m_static_mappings[index]);
} else {
// Allocate a page for the extra mappings.
if (m_mappings == nullptr) {
KPageBuffer* page_buffer = KPageBuffer::Allocate(kernel);
KPageBuffer* page_buffer = KPageBuffer::Allocate(m_kernel);
R_UNLESS(page_buffer != nullptr, ResultOutOfMemory);
m_mappings = reinterpret_cast<Mapping*>(page_buffer);
}
mapping = &m_mappings[index - NumStaticMappings];
mapping = std::addressof(m_mappings[index - NumStaticMappings]);
}
// Set the mapping.
mapping->Set(client, server, size, state);
return ResultSuccess;
R_SUCCEED();
}
Result KSessionRequest::SessionMappings::PushSend(VAddr client, VAddr server, size_t size,
KMemoryState state) {
Result KSessionRequest::SessionMappings::PushSend(KProcessAddress client, KProcessAddress server,
size_t size, KMemoryState state) {
ASSERT(m_num_recv == 0);
ASSERT(m_num_exch == 0);
return this->PushMap(client, server, size, state, m_num_send++);
R_RETURN(this->PushMap(client, server, size, state, m_num_send++));
}
Result KSessionRequest::SessionMappings::PushReceive(VAddr client, VAddr server, size_t size,
KMemoryState state) {
Result KSessionRequest::SessionMappings::PushReceive(KProcessAddress client, KProcessAddress server,
size_t size, KMemoryState state) {
ASSERT(m_num_exch == 0);
return this->PushMap(client, server, size, state, m_num_send + m_num_recv++);
R_RETURN(this->PushMap(client, server, size, state, m_num_send + m_num_recv++));
}
Result KSessionRequest::SessionMappings::PushExchange(VAddr client, VAddr server, size_t size,
Result KSessionRequest::SessionMappings::PushExchange(KProcessAddress client,
KProcessAddress server, size_t size,
KMemoryState state) {
return this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++);
R_RETURN(this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++));
}
void KSessionRequest::SessionMappings::Finalize() {
if (m_mappings) {
KPageBuffer::Free(kernel, reinterpret_cast<KPageBuffer*>(m_mappings));
KPageBuffer::Free(m_kernel, reinterpret_cast<KPageBuffer*>(m_mappings));
m_mappings = nullptr;
}
}

View File

@@ -26,17 +26,17 @@ public:
class Mapping {
public:
constexpr void Set(VAddr c, VAddr s, size_t sz, KMemoryState st) {
constexpr void Set(KProcessAddress c, KProcessAddress s, size_t sz, KMemoryState st) {
m_client_address = c;
m_server_address = s;
m_size = sz;
m_state = st;
}
constexpr VAddr GetClientAddress() const {
constexpr KProcessAddress GetClientAddress() const {
return m_client_address;
}
constexpr VAddr GetServerAddress() const {
constexpr KProcessAddress GetServerAddress() const {
return m_server_address;
}
constexpr size_t GetSize() const {
@@ -47,14 +47,14 @@ public:
}
private:
VAddr m_client_address;
VAddr m_server_address;
size_t m_size;
KMemoryState m_state;
KProcessAddress m_client_address{};
KProcessAddress m_server_address{};
size_t m_size{};
KMemoryState m_state{};
};
public:
explicit SessionMappings(KernelCore& kernel_) : kernel(kernel_) {}
explicit SessionMappings(KernelCore& kernel) : m_kernel(kernel) {}
void Initialize() {}
void Finalize();
@@ -69,14 +69,17 @@ public:
return m_num_exch;
}
Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state);
Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state);
Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state);
Result PushSend(KProcessAddress client, KProcessAddress server, size_t size,
KMemoryState state);
Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size,
KMemoryState state);
Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size,
KMemoryState state);
VAddr GetSendClientAddress(size_t i) const {
KProcessAddress GetSendClientAddress(size_t i) const {
return GetSendMapping(i).GetClientAddress();
}
VAddr GetSendServerAddress(size_t i) const {
KProcessAddress GetSendServerAddress(size_t i) const {
return GetSendMapping(i).GetServerAddress();
}
size_t GetSendSize(size_t i) const {
@@ -86,10 +89,10 @@ public:
return GetSendMapping(i).GetMemoryState();
}
VAddr GetReceiveClientAddress(size_t i) const {
KProcessAddress GetReceiveClientAddress(size_t i) const {
return GetReceiveMapping(i).GetClientAddress();
}
VAddr GetReceiveServerAddress(size_t i) const {
KProcessAddress GetReceiveServerAddress(size_t i) const {
return GetReceiveMapping(i).GetServerAddress();
}
size_t GetReceiveSize(size_t i) const {
@@ -99,10 +102,10 @@ public:
return GetReceiveMapping(i).GetMemoryState();
}
VAddr GetExchangeClientAddress(size_t i) const {
KProcessAddress GetExchangeClientAddress(size_t i) const {
return GetExchangeMapping(i).GetClientAddress();
}
VAddr GetExchangeServerAddress(size_t i) const {
KProcessAddress GetExchangeServerAddress(size_t i) const {
return GetExchangeMapping(i).GetServerAddress();
}
size_t GetExchangeSize(size_t i) const {
@@ -113,7 +116,8 @@ public:
}
private:
Result PushMap(VAddr client, VAddr server, size_t size, KMemoryState state, size_t index);
Result PushMap(KProcessAddress client, KProcessAddress server, size_t size,
KMemoryState state, size_t index);
const Mapping& GetSendMapping(size_t i) const {
ASSERT(i < m_num_send);
@@ -149,8 +153,8 @@ public:
}
private:
KernelCore& kernel;
std::array<Mapping, NumStaticMappings> m_static_mappings;
KernelCore& m_kernel;
std::array<Mapping, NumStaticMappings> m_static_mappings{};
Mapping* m_mappings{};
u8 m_num_send{};
u8 m_num_recv{};
@@ -158,7 +162,7 @@ public:
};
public:
explicit KSessionRequest(KernelCore& kernel_) : KAutoObject(kernel_), m_mappings(kernel_) {}
explicit KSessionRequest(KernelCore& kernel) : KAutoObject(kernel), m_mappings(kernel) {}
static KSessionRequest* Create(KernelCore& kernel) {
KSessionRequest* req = KSessionRequest::Allocate(kernel);
@@ -170,13 +174,13 @@ public:
void Destroy() override {
this->Finalize();
KSessionRequest::Free(kernel, this);
KSessionRequest::Free(m_kernel, this);
}
void Initialize(KEvent* event, uintptr_t address, size_t size) {
m_mappings.Initialize();
m_thread = GetCurrentThreadPointer(kernel);
m_thread = GetCurrentThreadPointer(m_kernel);
m_event = event;
m_address = address;
m_size = size;
@@ -227,22 +231,25 @@ public:
return m_mappings.GetExchangeCount();
}
Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state) {
Result PushSend(KProcessAddress client, KProcessAddress server, size_t size,
KMemoryState state) {
return m_mappings.PushSend(client, server, size, state);
}
Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state) {
Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size,
KMemoryState state) {
return m_mappings.PushReceive(client, server, size, state);
}
Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state) {
Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size,
KMemoryState state) {
return m_mappings.PushExchange(client, server, size, state);
}
VAddr GetSendClientAddress(size_t i) const {
KProcessAddress GetSendClientAddress(size_t i) const {
return m_mappings.GetSendClientAddress(i);
}
VAddr GetSendServerAddress(size_t i) const {
KProcessAddress GetSendServerAddress(size_t i) const {
return m_mappings.GetSendServerAddress(i);
}
size_t GetSendSize(size_t i) const {
@@ -252,10 +259,10 @@ public:
return m_mappings.GetSendMemoryState(i);
}
VAddr GetReceiveClientAddress(size_t i) const {
KProcessAddress GetReceiveClientAddress(size_t i) const {
return m_mappings.GetReceiveClientAddress(i);
}
VAddr GetReceiveServerAddress(size_t i) const {
KProcessAddress GetReceiveServerAddress(size_t i) const {
return m_mappings.GetReceiveServerAddress(i);
}
size_t GetReceiveSize(size_t i) const {
@@ -265,10 +272,10 @@ public:
return m_mappings.GetReceiveMemoryState(i);
}
VAddr GetExchangeClientAddress(size_t i) const {
KProcessAddress GetExchangeClientAddress(size_t i) const {
return m_mappings.GetExchangeClientAddress(i);
}
VAddr GetExchangeServerAddress(size_t i) const {
KProcessAddress GetExchangeServerAddress(size_t i) const {
return m_mappings.GetExchangeServerAddress(i);
}
size_t GetExchangeSize(size_t i) const {

View File

@@ -12,29 +12,27 @@
namespace Kernel {
KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
KSharedMemory::KSharedMemory(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
KSharedMemory::~KSharedMemory() = default;
Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
Svc::MemoryPermission owner_permission_,
Svc::MemoryPermission user_permission_, std::size_t size_,
std::string name_) {
Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory, KProcess* owner_process,
Svc::MemoryPermission owner_permission,
Svc::MemoryPermission user_permission, std::size_t size) {
// Set members.
owner_process = owner_process_;
device_memory = &device_memory_;
owner_permission = owner_permission_;
user_permission = user_permission_;
size = Common::AlignUp(size_, PageSize);
name = std::move(name_);
m_owner_process = owner_process;
m_device_memory = std::addressof(device_memory);
m_owner_permission = owner_permission;
m_user_permission = user_permission;
m_size = Common::AlignUp(size, PageSize);
const size_t num_pages = Common::DivideUp(size, PageSize);
// Get the resource limit.
KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
KResourceLimit* reslimit = m_kernel.GetSystemResourceLimit();
// Reserve memory for ourselves.
KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemoryMax,
size_);
size);
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
// Allocate the memory.
@@ -42,67 +40,67 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
//! HACK: Open continuous mapping from sysmodule pool.
auto option = KMemoryManager::EncodeOption(KMemoryManager::Pool::Secure,
KMemoryManager::Direction::FromBack);
physical_address = kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, option);
R_UNLESS(physical_address != 0, ResultOutOfMemory);
m_physical_address = m_kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, option);
R_UNLESS(m_physical_address != 0, ResultOutOfMemory);
//! Insert the result into our page group.
page_group.emplace(kernel, &kernel.GetSystemSystemResource().GetBlockInfoManager());
page_group->AddBlock(physical_address, num_pages);
m_page_group.emplace(m_kernel,
std::addressof(m_kernel.GetSystemSystemResource().GetBlockInfoManager()));
m_page_group->AddBlock(m_physical_address, num_pages);
// Commit our reservation.
memory_reservation.Commit();
// Set our resource limit.
resource_limit = reslimit;
resource_limit->Open();
m_resource_limit = reslimit;
m_resource_limit->Open();
// Mark initialized.
is_initialized = true;
m_is_initialized = true;
// Clear all pages in the memory.
for (const auto& block : *page_group) {
std::memset(device_memory_.GetPointer<void>(block.GetAddress()), 0, block.GetSize());
for (const auto& block : *m_page_group) {
std::memset(m_device_memory->GetPointer<void>(block.GetAddress()), 0, block.GetSize());
}
return ResultSuccess;
R_SUCCEED();
}
void KSharedMemory::Finalize() {
// Close and finalize the page group.
page_group->Close();
page_group->Finalize();
m_page_group->Close();
m_page_group->Finalize();
// Release the memory reservation.
resource_limit->Release(LimitableResource::PhysicalMemoryMax, size);
resource_limit->Close();
// Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList>::Finalize();
m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, m_size);
m_resource_limit->Close();
}
Result KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t map_size,
Result KSharedMemory::Map(KProcess& target_process, KProcessAddress address, std::size_t map_size,
Svc::MemoryPermission map_perm) {
// Validate the size.
R_UNLESS(size == map_size, ResultInvalidSize);
R_UNLESS(m_size == map_size, ResultInvalidSize);
// Validate the permission.
const Svc::MemoryPermission test_perm =
&target_process == owner_process ? owner_permission : user_permission;
std::addressof(target_process) == m_owner_process ? m_owner_permission : m_user_permission;
if (test_perm == Svc::MemoryPermission::DontCare) {
ASSERT(map_perm == Svc::MemoryPermission::Read || map_perm == Svc::MemoryPermission::Write);
} else {
R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission);
}
return target_process.PageTable().MapPageGroup(address, *page_group, KMemoryState::Shared,
ConvertToKMemoryPermission(map_perm));
R_RETURN(target_process.PageTable().MapPageGroup(address, *m_page_group, KMemoryState::Shared,
ConvertToKMemoryPermission(map_perm)));
}
Result KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) {
Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address,
std::size_t unmap_size) {
// Validate the size.
R_UNLESS(size == unmap_size, ResultInvalidSize);
R_UNLESS(m_size == unmap_size, ResultInvalidSize);
return target_process.PageTable().UnmapPageGroup(address, *page_group, KMemoryState::Shared);
R_RETURN(
target_process.PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::Shared));
}
} // namespace Kernel

View File

@@ -6,11 +6,11 @@
#include <optional>
#include <string>
#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
@@ -23,12 +23,12 @@ class KSharedMemory final
KERNEL_AUTOOBJECT_TRAITS(KSharedMemory, KAutoObject);
public:
explicit KSharedMemory(KernelCore& kernel_);
explicit KSharedMemory(KernelCore& kernel);
~KSharedMemory() override;
Result Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
Svc::MemoryPermission owner_permission_,
Svc::MemoryPermission user_permission_, std::size_t size_, std::string name_);
Svc::MemoryPermission user_permission_, std::size_t size_);
/**
* Maps a shared memory block to an address in the target process' address space
@@ -37,7 +37,7 @@ public:
* @param map_size Size of the shared memory block to map
* @param permissions Memory block map permissions (specified by SVC field)
*/
Result Map(KProcess& target_process, VAddr address, std::size_t map_size,
Result Map(KProcess& target_process, KProcessAddress address, std::size_t map_size,
Svc::MemoryPermission permissions);
/**
@@ -46,7 +46,7 @@ public:
* @param address Address in system memory to unmap shared memory block
* @param unmap_size Size of the shared memory block to unmap
*/
Result Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size);
Result Unmap(KProcess& target_process, KProcessAddress address, std::size_t unmap_size);
/**
* Gets a pointer to the shared memory block
@@ -54,7 +54,7 @@ public:
* @return A pointer to the shared memory block from the specified offset
*/
u8* GetPointer(std::size_t offset = 0) {
return device_memory->GetPointer<u8>(physical_address + offset);
return m_device_memory->GetPointer<u8>(m_physical_address + offset);
}
/**
@@ -63,26 +63,26 @@ public:
* @return A pointer to the shared memory block from the specified offset
*/
const u8* GetPointer(std::size_t offset = 0) const {
return device_memory->GetPointer<u8>(physical_address + offset);
return m_device_memory->GetPointer<u8>(m_physical_address + offset);
}
void Finalize() override;
bool IsInitialized() const override {
return is_initialized;
return m_is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
static void PostDestroy(uintptr_t arg) {}
private:
Core::DeviceMemory* device_memory{};
KProcess* owner_process{};
std::optional<KPageGroup> page_group{};
Svc::MemoryPermission owner_permission{};
Svc::MemoryPermission user_permission{};
PAddr physical_address{};
std::size_t size{};
KResourceLimit* resource_limit{};
bool is_initialized{};
Core::DeviceMemory* m_device_memory{};
KProcess* m_owner_process{};
std::optional<KPageGroup> m_page_group{};
Svc::MemoryPermission m_owner_permission{};
Svc::MemoryPermission m_user_permission{};
KPhysicalAddress m_physical_address{};
std::size_t m_size{};
KResourceLimit* m_resource_limit{};
bool m_is_initialized{};
};
} // namespace Kernel

View File

@@ -18,25 +18,28 @@ public:
explicit KSharedMemoryInfo(KernelCore&) {}
KSharedMemoryInfo() = default;
constexpr void Initialize(KSharedMemory* shmem) {
shared_memory = shmem;
constexpr void Initialize(KSharedMemory* m) {
m_shared_memory = m;
m_reference_count = 0;
}
constexpr KSharedMemory* GetSharedMemory() const {
return shared_memory;
return m_shared_memory;
}
constexpr void Open() {
++reference_count;
++m_reference_count;
ASSERT(m_reference_count > 0);
}
constexpr bool Close() {
return (--reference_count) == 0;
ASSERT(m_reference_count > 0);
return (--m_reference_count) == 0;
}
private:
KSharedMemory* shared_memory{};
size_t reference_count{};
KSharedMemory* m_shared_memory{};
size_t m_reference_count{};
};
} // namespace Kernel

Some files were not shown because too many files have changed in this diff Show More