diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/page_table.cpp | 10 | ||||
| -rw-r--r-- | src/common/page_table.h | 68 | ||||
| -rw-r--r-- | src/common/virtual_buffer.h | 10 |
3 files changed, 65 insertions, 23 deletions
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp index bccea0894..8fd8620fd 100644 --- a/src/common/page_table.cpp +++ b/src/common/page_table.cpp | |||
| @@ -10,16 +10,10 @@ PageTable::PageTable() = default; | |||
| 10 | 10 | ||
| 11 | PageTable::~PageTable() noexcept = default; | 11 | PageTable::~PageTable() noexcept = default; |
| 12 | 12 | ||
| 13 | void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, | 13 | void PageTable::Resize(size_t address_space_width_in_bits, size_t page_size_in_bits) { |
| 14 | bool has_attribute) { | 14 | const size_t num_page_table_entries{1ULL << (address_space_width_in_bits - page_size_in_bits)}; |
| 15 | const std::size_t num_page_table_entries{1ULL | ||
| 16 | << (address_space_width_in_bits - page_size_in_bits)}; | ||
| 17 | pointers.resize(num_page_table_entries); | 15 | pointers.resize(num_page_table_entries); |
| 18 | backing_addr.resize(num_page_table_entries); | 16 | backing_addr.resize(num_page_table_entries); |
| 19 | |||
| 20 | if (has_attribute) { | ||
| 21 | attributes.resize(num_page_table_entries); | ||
| 22 | } | ||
| 23 | } | 17 | } |
| 24 | 18 | ||
| 25 | } // namespace Common | 19 | } // namespace Common |
diff --git a/src/common/page_table.h b/src/common/page_table.h index 9754fabf9..8d4ee9249 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | ||
| 7 | #include <tuple> | 8 | #include <tuple> |
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| @@ -20,10 +21,6 @@ enum class PageType : u8 { | |||
| 20 | /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and | 21 | /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and |
| 21 | /// invalidation | 22 | /// invalidation |
| 22 | RasterizerCachedMemory, | 23 | RasterizerCachedMemory, |
| 23 | /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions. | ||
| 24 | Special, | ||
| 25 | /// Page is allocated for use. | ||
| 26 | Allocated, | ||
| 27 | }; | 24 | }; |
| 28 | 25 | ||
| 29 | struct SpecialRegion { | 26 | struct SpecialRegion { |
| @@ -48,6 +45,59 @@ struct SpecialRegion { | |||
| 48 | * mimics the way a real CPU page table works. | 45 | * mimics the way a real CPU page table works. |
| 49 | */ | 46 | */ |
| 50 | struct PageTable { | 47 | struct PageTable { |
| 48 | /// Number of bits reserved for attribute tagging. | ||
| 49 | /// This can be at most the guaranteed alignment of the pointers in the page table. | ||
| 50 | static constexpr int ATTRIBUTE_BITS = 2; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Pair of host pointer and page type attribute. | ||
| 54 | * This uses the lower bits of a given pointer to store the attribute tag. | ||
| 55 | * Writing and reading the pointer attribute pair is guaranteed to be atomic for the same method | ||
| 56 | * call. In other words, they are guaranteed to be synchronized at all times. | ||
| 57 | */ | ||
| 58 | class PageInfo { | ||
| 59 | public: | ||
| 60 | /// Returns the page pointer | ||
| 61 | [[nodiscard]] u8* Pointer() const noexcept { | ||
| 62 | return ExtractPointer(raw.load(std::memory_order_relaxed)); | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Returns the page type attribute | ||
| 66 | [[nodiscard]] PageType Type() const noexcept { | ||
| 67 | return ExtractType(raw.load(std::memory_order_relaxed)); | ||
| 68 | } | ||
| 69 | |||
| 70 | /// Returns the page pointer and attribute pair, extracted from the same atomic read | ||
| 71 | [[nodiscard]] std::pair<u8*, PageType> PointerType() const noexcept { | ||
| 72 | const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed); | ||
| 73 | return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)}; | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Returns the raw representation of the page information. | ||
| 77 | /// Use ExtractPointer and ExtractType to unpack the value. | ||
| 78 | [[nodiscard]] uintptr_t Raw() const noexcept { | ||
| 79 | return raw.load(std::memory_order_relaxed); | ||
| 80 | } | ||
| 81 | |||
| 82 | /// Write a page pointer and type pair atomically | ||
| 83 | void Store(u8* pointer, PageType type) noexcept { | ||
| 84 | raw.store(reinterpret_cast<uintptr_t>(pointer) | static_cast<uintptr_t>(type)); | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Unpack a pointer from a page info raw representation | ||
| 88 | [[nodiscard]] static u8* ExtractPointer(uintptr_t raw) noexcept { | ||
| 89 | return reinterpret_cast<u8*>(raw & (~uintptr_t{0} << ATTRIBUTE_BITS)); | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Unpack a page type from a page info raw representation | ||
| 93 | [[nodiscard]] static PageType ExtractType(uintptr_t raw) noexcept { | ||
| 94 | return static_cast<PageType>(raw & ((uintptr_t{1} << ATTRIBUTE_BITS) - 1)); | ||
| 95 | } | ||
| 96 | |||
| 97 | private: | ||
| 98 | std::atomic<uintptr_t> raw; | ||
| 99 | }; | ||
| 100 | |||
| 51 | PageTable(); | 101 | PageTable(); |
| 52 | ~PageTable() noexcept; | 102 | ~PageTable() noexcept; |
| 53 | 103 | ||
| @@ -63,20 +113,16 @@ struct PageTable { | |||
| 63 | * | 113 | * |
| 64 | * @param address_space_width_in_bits The address size width in bits. | 114 | * @param address_space_width_in_bits The address size width in bits. |
| 65 | * @param page_size_in_bits The page size in bits. | 115 | * @param page_size_in_bits The page size in bits. |
| 66 | * @param has_attribute Whether or not this page has any backing attributes. | ||
| 67 | */ | 116 | */ |
| 68 | void Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, | 117 | void Resize(size_t address_space_width_in_bits, size_t page_size_in_bits); |
| 69 | bool has_attribute); | ||
| 70 | 118 | ||
| 71 | /** | 119 | /** |
| 72 | * Vector of memory pointers backing each page. An entry can only be non-null if the | 120 | * Vector of memory pointers backing each page. An entry can only be non-null if the |
| 73 | * corresponding entry in the `attributes` vector is of type `Memory`. | 121 | * corresponding attribute element is of type `Memory`. |
| 74 | */ | 122 | */ |
| 75 | VirtualBuffer<u8*> pointers; | 123 | VirtualBuffer<PageInfo> pointers; |
| 76 | 124 | ||
| 77 | VirtualBuffer<u64> backing_addr; | 125 | VirtualBuffer<u64> backing_addr; |
| 78 | |||
| 79 | VirtualBuffer<PageType> attributes; | ||
| 80 | }; | 126 | }; |
| 81 | 127 | ||
| 82 | } // namespace Common | 128 | } // namespace Common |
diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 91d430036..fb1a6f81f 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h | |||
| @@ -15,10 +15,12 @@ void FreeMemoryPages(void* base, std::size_t size) noexcept; | |||
| 15 | template <typename T> | 15 | template <typename T> |
| 16 | class VirtualBuffer final { | 16 | class VirtualBuffer final { |
| 17 | public: | 17 | public: |
| 18 | static_assert( | 18 | // TODO: Uncomment this and change Common::PageTable::PageInfo to be trivially constructible |
| 19 | std::is_trivially_constructible_v<T>, | 19 | // using std::atomic_ref once libc++ has support for it |
| 20 | "T must be trivially constructible, as non-trivial constructors will not be executed " | 20 | // static_assert( |
| 21 | "with the current allocator"); | 21 | // std::is_trivially_constructible_v<T>, |
| 22 | // "T must be trivially constructible, as non-trivial constructors will not be executed " | ||
| 23 | // "with the current allocator"); | ||
| 22 | 24 | ||
| 23 | constexpr VirtualBuffer() = default; | 25 | constexpr VirtualBuffer() = default; |
| 24 | explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { | 26 | explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { |