summaryrefslogtreecommitdiffstats
path: root/src/common/multi_level_page_table.h
blob: 08092c89a660ad735159902ee1a902315d14061c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <type_traits>
#include <utility>
#include <vector>

#include "common/common_types.h"

namespace Common {

template <typename BaseAddr>
class MultiLevelPageTable final {
public:
    constexpr MultiLevelPageTable() = default;
    explicit MultiLevelPageTable(std::size_t address_space_bits, std::size_t first_level_bits,
                                 std::size_t page_bits);

    ~MultiLevelPageTable() noexcept;

    MultiLevelPageTable(const MultiLevelPageTable&) = delete;
    MultiLevelPageTable& operator=(const MultiLevelPageTable&) = delete;

    MultiLevelPageTable(MultiLevelPageTable&& other) noexcept
        : address_space_bits{std::exchange(other.address_space_bits, 0)},
          first_level_bits{std::exchange(other.first_level_bits, 0)}, page_bits{std::exchange(
                                                                          other.page_bits, 0)},
          first_level_shift{std::exchange(other.first_level_shift, 0)},
          first_level_chunk_size{std::exchange(other.first_level_chunk_size, 0)},
          first_level_map{std::move(other.first_level_map)}, base_ptr{std::exchange(other.base_ptr,
                                                                                    nullptr)} {}

    MultiLevelPageTable& operator=(MultiLevelPageTable&& other) noexcept {
        address_space_bits = std::exchange(other.address_space_bits, 0);
        first_level_bits = std::exchange(other.first_level_bits, 0);
        page_bits = std::exchange(other.page_bits, 0);
        first_level_shift = std::exchange(other.first_level_shift, 0);
        first_level_chunk_size = std::exchange(other.first_level_chunk_size, 0);
        alloc_size = std::exchange(other.alloc_size, 0);
        first_level_map = std::move(other.first_level_map);
        base_ptr = std::exchange(other.base_ptr, nullptr);
        return *this;
    }

    void ReserveRange(u64 start, std::size_t size);

    [[nodiscard]] constexpr const BaseAddr& operator[](std::size_t index) const {
        return base_ptr[index];
    }

    [[nodiscard]] constexpr BaseAddr& operator[](std::size_t index) {
        return base_ptr[index];
    }

    [[nodiscard]] constexpr BaseAddr* data() {
        return base_ptr;
    }

    [[nodiscard]] constexpr const BaseAddr* data() const {
        return base_ptr;
    }

private:
    void AllocateLevel(u64 level);

    std::size_t address_space_bits{};
    std::size_t first_level_bits{};
    std::size_t page_bits{};
    std::size_t first_level_shift{};
    std::size_t first_level_chunk_size{};
    std::size_t alloc_size{};
    std::vector<void*> first_level_map{};
    BaseAddr* base_ptr{};
};

} // namespace Common