2022-12-29 09:39:42 +01:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
2022-04-23 10:59:50 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2020-04-05 21:03:31 +02:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
|
2022-10-29 22:49:09 +02:00
|
|
|
#include "common/alignment.h"
|
2020-04-05 21:03:31 +02:00
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/common_types.h"
|
2021-02-13 02:02:51 +01:00
|
|
|
#include "core/hle/kernel/memory_types.h"
|
2020-04-05 21:03:31 +02:00
|
|
|
#include "core/hle/result.h"
|
|
|
|
|
2021-02-13 02:26:01 +01:00
|
|
|
namespace Kernel {
|
2020-04-05 21:03:31 +02:00
|
|
|
|
2022-10-29 22:49:09 +02:00
|
|
|
class KPageGroup;
|
|
|
|
|
|
|
|
class KBlockInfo {
|
2022-12-29 09:39:42 +01:00
|
|
|
private:
|
|
|
|
friend class KPageGroup;
|
|
|
|
|
2022-10-29 22:49:09 +02:00
|
|
|
public:
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr KBlockInfo() = default;
|
2022-10-29 22:49:09 +02:00
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr void Initialize(PAddr addr, size_t np) {
|
2022-10-29 22:49:09 +02:00
|
|
|
ASSERT(Common::IsAligned(addr, PageSize));
|
|
|
|
ASSERT(static_cast<u32>(np) == np);
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
m_page_index = static_cast<u32>(addr) / PageSize;
|
2022-10-29 22:49:09 +02:00
|
|
|
m_num_pages = static_cast<u32>(np);
|
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr PAddr GetAddress() const {
|
2022-10-29 22:49:09 +02:00
|
|
|
return m_page_index * PageSize;
|
|
|
|
}
|
|
|
|
constexpr size_t GetNumPages() const {
|
|
|
|
return m_num_pages;
|
|
|
|
}
|
|
|
|
constexpr size_t GetSize() const {
|
|
|
|
return this->GetNumPages() * PageSize;
|
|
|
|
}
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr PAddr GetEndAddress() const {
|
2022-10-29 22:49:09 +02:00
|
|
|
return (m_page_index + m_num_pages) * PageSize;
|
|
|
|
}
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr PAddr GetLastAddress() const {
|
2022-10-29 22:49:09 +02:00
|
|
|
return this->GetEndAddress() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr KBlockInfo* GetNext() const {
|
|
|
|
return m_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool IsEquivalentTo(const KBlockInfo& rhs) const {
|
|
|
|
return m_page_index == rhs.m_page_index && m_num_pages == rhs.m_num_pages;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator==(const KBlockInfo& rhs) const {
|
|
|
|
return this->IsEquivalentTo(rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator!=(const KBlockInfo& rhs) const {
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr bool IsStrictlyBefore(PAddr addr) const {
|
|
|
|
const PAddr end = this->GetEndAddress();
|
2022-10-29 22:49:09 +02:00
|
|
|
|
|
|
|
if (m_page_index != 0 && end == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return end < addr;
|
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr bool operator<(PAddr addr) const {
|
2022-10-29 22:49:09 +02:00
|
|
|
return this->IsStrictlyBefore(addr);
|
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr bool TryConcatenate(PAddr addr, size_t np) {
|
2022-10-29 22:49:09 +02:00
|
|
|
if (addr != 0 && addr == this->GetEndAddress()) {
|
|
|
|
m_num_pages += static_cast<u32>(np);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
constexpr void SetNext(KBlockInfo* next) {
|
|
|
|
m_next = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
KBlockInfo* m_next{};
|
|
|
|
u32 m_page_index{};
|
|
|
|
u32 m_num_pages{};
|
|
|
|
};
|
|
|
|
static_assert(sizeof(KBlockInfo) <= 0x10);
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
class KPageGroup final {
|
2020-04-05 21:03:31 +02:00
|
|
|
public:
|
2022-12-29 09:39:42 +01:00
|
|
|
class Node final {
|
2020-04-05 21:03:31 +02:00
|
|
|
public:
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {}
|
2020-04-05 21:03:31 +02:00
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr u64 GetAddress() const {
|
|
|
|
return addr;
|
2020-04-05 21:03:31 +02:00
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr std::size_t GetNumPages() const {
|
|
|
|
return num_pages;
|
2020-04-05 21:03:31 +02:00
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr std::size_t GetSize() const {
|
|
|
|
return GetNumPages() * PageSize;
|
2021-12-05 21:04:08 +01:00
|
|
|
}
|
|
|
|
|
2020-04-05 21:03:31 +02:00
|
|
|
private:
|
2022-12-29 09:39:42 +01:00
|
|
|
u64 addr{};
|
|
|
|
std::size_t num_pages{};
|
2020-04-05 21:03:31 +02:00
|
|
|
};
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
public:
|
|
|
|
KPageGroup() = default;
|
|
|
|
KPageGroup(u64 address, u64 num_pages) {
|
|
|
|
ASSERT(AddBlock(address, num_pages).IsSuccess());
|
2020-04-05 21:03:31 +02:00
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr std::list<Node>& Nodes() {
|
|
|
|
return nodes;
|
2020-04-05 21:03:31 +02:00
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
constexpr const std::list<Node>& Nodes() const {
|
|
|
|
return nodes;
|
2022-12-24 03:32:13 +01:00
|
|
|
}
|
2020-04-05 21:03:31 +02:00
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
std::size_t GetNumPages() const {
|
|
|
|
std::size_t num_pages = 0;
|
|
|
|
for (const Node& node : nodes) {
|
|
|
|
num_pages += node.GetNumPages();
|
|
|
|
}
|
|
|
|
return num_pages;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsEqual(KPageGroup& other) const {
|
|
|
|
auto this_node = nodes.begin();
|
|
|
|
auto other_node = other.nodes.begin();
|
|
|
|
while (this_node != nodes.end() && other_node != other.nodes.end()) {
|
|
|
|
if (this_node->GetAddress() != other_node->GetAddress() ||
|
|
|
|
this_node->GetNumPages() != other_node->GetNumPages()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this_node = std::next(this_node);
|
|
|
|
other_node = std::next(other_node);
|
|
|
|
}
|
2020-04-05 21:03:31 +02:00
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
return this_node == nodes.end() && other_node == other.nodes.end();
|
|
|
|
}
|
2022-12-24 03:32:13 +01:00
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
Result AddBlock(u64 address, u64 num_pages) {
|
|
|
|
if (!num_pages) {
|
|
|
|
return ResultSuccess;
|
2020-04-05 21:03:31 +02:00
|
|
|
}
|
2022-12-29 09:39:42 +01:00
|
|
|
if (!nodes.empty()) {
|
|
|
|
const auto node = nodes.back();
|
|
|
|
if (node.GetAddress() + node.GetNumPages() * PageSize == address) {
|
|
|
|
address = node.GetAddress();
|
|
|
|
num_pages += node.GetNumPages();
|
|
|
|
nodes.pop_back();
|
|
|
|
}
|
2020-04-05 21:03:31 +02:00
|
|
|
}
|
2022-12-29 09:39:42 +01:00
|
|
|
nodes.push_back({address, num_pages});
|
|
|
|
return ResultSuccess;
|
2020-04-05 21:03:31 +02:00
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
bool Empty() const {
|
|
|
|
return nodes.empty();
|
2022-03-26 09:02:42 +01:00
|
|
|
}
|
|
|
|
|
2022-12-29 09:39:42 +01:00
|
|
|
void Finalize() {}
|
|
|
|
|
2020-04-05 21:03:31 +02:00
|
|
|
private:
|
2022-12-29 09:39:42 +01:00
|
|
|
std::list<Node> nodes;
|
2020-04-05 21:03:31 +02:00
|
|
|
};
|
|
|
|
|
2021-02-13 02:26:01 +01:00
|
|
|
} // namespace Kernel
|