Compare commits
77 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7e7944350 | ||
|
|
8b0dc68848 | ||
|
|
09da9da6fb | ||
|
|
6892a0942f | ||
|
|
f38ae8e953 | ||
|
|
cfb9672093 | ||
|
|
462c430c8b | ||
|
|
5a2dff87bf | ||
|
|
7a8a7545f2 | ||
|
|
abe2ad7aac | ||
|
|
877e8991c7 | ||
|
|
032e5b983c | ||
|
|
ac3927074b | ||
|
|
c41a4baf06 | ||
|
|
6adaa0d5e2 | ||
|
|
fb49ec19c1 | ||
|
|
197d756560 | ||
|
|
8c56481249 | ||
|
|
6ff4bf9b1c | ||
|
|
dba86ee007 | ||
|
|
407dc917f1 | ||
|
|
15d573194c | ||
|
|
f28ca5361f | ||
|
|
306840a580 | ||
|
|
3d4c113037 | ||
|
|
230d118252 | ||
|
|
b9b1318bea | ||
|
|
43d909949e | ||
|
|
00d401d639 | ||
|
|
0e7e98e24e | ||
|
|
0eb3fa05e5 | ||
|
|
889454f9bf | ||
|
|
8bcaa8c2e4 | ||
|
|
c95baf92ce | ||
|
|
a7651168dd | ||
|
|
075a3d1172 | ||
|
|
6d76a54d37 | ||
|
|
a04061e6ae | ||
|
|
7187732454 | ||
|
|
5031f5b8b0 | ||
|
|
da83afdeaf | ||
|
|
026fe2e4f4 | ||
|
|
0c7149d222 | ||
|
|
05f26e1337 | ||
|
|
4c678cfbc8 | ||
|
|
8870fae674 | ||
|
|
8348c41eab | ||
|
|
638044820d | ||
|
|
1f952f6ac9 | ||
|
|
96b8a3ecac | ||
|
|
c352381ce9 | ||
|
|
9775a73d1a | ||
|
|
088c434d65 | ||
|
|
9863db9db4 | ||
|
|
6bfb4c8f71 | ||
|
|
ac6cbb7134 | ||
|
|
641783df8f | ||
|
|
c0b9e93b77 | ||
|
|
9368e17a92 | ||
|
|
91fd4e30f2 | ||
|
|
57f1d8ef8d | ||
|
|
d1b53c8d82 | ||
|
|
7322c99e5f | ||
|
|
467adc1acd | ||
|
|
0483dfae1a | ||
|
|
8d1f5bfbd2 | ||
|
|
fdf90c6d75 | ||
|
|
097c25b164 | ||
|
|
d24ab14126 | ||
|
|
54c359d1e3 | ||
|
|
3f261f22c9 | ||
|
|
44f10c8dee | ||
|
|
4e42ba54e5 | ||
|
|
e090a1c6bd | ||
|
|
e8af3f29d2 | ||
|
|
c8ad039612 | ||
|
|
44518b225c |
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
320
src/common/typed_address.h
Normal 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
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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{};
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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{};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user