diff options
author | Gabe Black <gabeblack@google.com> | 2018-01-08 04:41:25 -0800 |
---|---|---|
committer | Gabe Black <gabeblack@google.com> | 2018-01-23 20:14:48 +0000 |
commit | db8c55dede65e07cb9ea8e95c48badd2ea24462f (patch) | |
tree | 8b8b4fad738f3ecd3907bb6157517cc0e8a822eb /src/mem/multi_level_page_table.hh | |
parent | 8cb6bb444a6ee0106807d0a22bbc63323b410bf8 (diff) | |
download | gem5-db8c55dede65e07cb9ea8e95c48badd2ea24462f.tar.xz |
x86, mem: Rewrite the multilevel page table class.
The new version extracts all the x86 specific aspects of the class,
and builds the interface around a variable collection of template
arguments which are classes that represent the different levels of the
page table. The multilevel page table class is now much more ISA
independent.
Change-Id: Id42e168a78d0e70f80ab2438480cb6e00a3aa636
Reviewed-on: https://gem5-review.googlesource.com/7347
Reviewed-by: Brandon Potter <Brandon.Potter@amd.com>
Maintainer: Gabe Black <gabeblack@google.com>
Diffstat (limited to 'src/mem/multi_level_page_table.hh')
-rw-r--r-- | src/mem/multi_level_page_table.hh | 206 |
1 files changed, 170 insertions, 36 deletions
diff --git a/src/mem/multi_level_page_table.hh b/src/mem/multi_level_page_table.hh index 30f534706..bd40d37c1 100644 --- a/src/mem/multi_level_page_table.hh +++ b/src/mem/multi_level_page_table.hh @@ -39,7 +39,6 @@ #include <string> #include "base/types.hh" -#include "config/the_isa.hh" #include "mem/page_table.hh" class System; @@ -99,13 +98,90 @@ class System; * * @see MultiLevelPageTable */ -template <class ISAOps> + +namespace { + +template <class First, class ...Rest> +Addr +prepTopTable(System *system, Addr pageSize) +{ + Addr addr = system->allocPhysPages(First::tableSize()); + PortProxy &p = system->physProxy; + p.memsetBlob(addr, 0, First::tableSize() * pageSize); + return addr; +} + +template <class ...Types> +struct LastType; + +template <class First, class Second, class ...Rest> +struct LastType<First, Second, Rest...> +{ + typedef typename LastType<Second, Rest...>::type type; +}; + +template <class Only> +struct LastType<Only> +{ + typedef Only type; +}; + + +template <class ...Types> +struct WalkWrapper; + +template <class Final, class Only> +struct WalkWrapper<Final, Only> +{ + static void + walk(System *system, Addr pageSize, Addr table, Addr vaddr, + bool allocate, Final *entry) + { + entry->read(system->physProxy, table, vaddr); + } +}; + +template <class Final, class First, class Second, class ...Rest> +struct WalkWrapper<Final, First, Second, Rest...> +{ + static void + walk(System *system, Addr pageSize, Addr table, Addr vaddr, + bool allocate, Final *entry) + { + First first; + first.read(system->physProxy, table, vaddr); + + Addr next; + if (!first.present()) { + fatal_if(!allocate, + "Page fault while walking the page table."); + next = prepTopTable<Second>(system, pageSize); + first.reset(next); + first.write(system->physProxy); + } else { + next = first.paddr(); + } + WalkWrapper<Final, Second, Rest...>::walk( + system, pageSize, next, vaddr, allocate, entry); + } +}; + +template <class ...EntryTypes> +void +walk(System *system, Addr pageSize, Addr table, Addr vaddr, + bool allocate, typename LastType<EntryTypes...>::type *entry) +{ + WalkWrapper<typename LastType<EntryTypes...>::type, EntryTypes...>::walk( + system, pageSize, table, vaddr, allocate, entry); +} + +} + + +template <class ...EntryTypes> class MultiLevelPageTable : public EmulationPageTable { - /** - * ISA specific operations - */ - ISAOps pTableISAOps; + typedef typename LastType<EntryTypes...>::type Final; /** * Pointer to System object @@ -117,41 +193,99 @@ class MultiLevelPageTable : public EmulationPageTable */ Addr _basePtr; - /** - * Vector with sizes of all levels in base 2 logarithmic - */ - const std::vector<uint8_t> logLevelSize; - - /** - * Number of levels contained by the page table - */ - const uint64_t numLevels; - - /** - * Method for walking the page table - * - * @param vaddr Virtual address that is being looked-up - * @param allocate Specifies whether memory should be allocated while - * walking the page table - * @return PTE_addr The address of the found PTE - */ - void walk(Addr vaddr, bool allocate, Addr &PTE_addr); - public: MultiLevelPageTable(const std::string &__name, uint64_t _pid, - System *_sys, Addr pageSize, - const std::vector<uint8_t> &layout); - ~MultiLevelPageTable(); + System *_sys, Addr pageSize) : + EmulationPageTable(__name, _pid, pageSize), system(_sys) + {} + + ~MultiLevelPageTable() {} - void initState(ThreadContext* tc) override; + void + initState(ThreadContext* tc) override + { + _basePtr = prepTopTable<EntryTypes...>(system, pageSize); + } Addr basePtr() { return _basePtr; } - void map(Addr vaddr, Addr paddr, int64_t size, - uint64_t flags = 0) override; - void remap(Addr vaddr, int64_t size, Addr new_vaddr) override; - void unmap(Addr vaddr, int64_t size) override; - void serialize(CheckpointOut &cp) const override; - void unserialize(CheckpointIn &cp) override; + void + map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags = 0) override + { + EmulationPageTable::map(vaddr, paddr, size, flags); + + Final entry; + + for (int64_t offset = 0; offset < size; offset += pageSize) { + walk<EntryTypes...>(system, pageSize, _basePtr, + vaddr + offset, true, &entry); + + entry.reset(paddr + offset, true, flags & Uncacheable, + flags & ReadOnly); + entry.write(system->physProxy); + + DPRINTF(MMU, "New mapping: %#x-%#x\n", + vaddr + offset, paddr + offset); + } + } + + void + remap(Addr vaddr, int64_t size, Addr new_vaddr) override + { + EmulationPageTable::remap(vaddr, size, new_vaddr); + + Final old_entry, new_entry; + + for (int64_t offset = 0; offset < size; offset += pageSize) { + // Unmap the original mapping. + walk<EntryTypes...>(system, pageSize, _basePtr, vaddr + offset, + false, &old_entry); + old_entry.present(false); + old_entry.write(system->physProxy); + + // Map the new one. + walk<EntryTypes...>(system, pageSize, _basePtr, new_vaddr + offset, + true, &new_entry); + new_entry.reset(old_entry.paddr(), true, old_entry.uncacheable(), + old_entry.readonly()); + new_entry.write(system->physProxy); + } + } + + void + unmap(Addr vaddr, int64_t size) override + { + EmulationPageTable::unmap(vaddr, size); + + Final entry; + + for (int64_t offset = 0; offset < size; offset += pageSize) { + walk<EntryTypes...>(system, pageSize, _basePtr, + vaddr + offset, false, &entry); + fatal_if(!entry.present(), + "PageTable::unmap: Address %#x not mapped.", vaddr); + entry.present(false); + entry.write(system->physProxy); + DPRINTF(MMU, "Unmapping: %#x\n", vaddr); + } + } + + void + serialize(CheckpointOut &cp) const override + { + EmulationPageTable::serialize(cp); + /** Since, the page table is stored in system memory + * which is serialized separately, we will serialize + * just the base pointer + */ + paramOut(cp, "ptable.pointer", _basePtr); + } + + void + unserialize(CheckpointIn &cp) override + { + EmulationPageTable::unserialize(cp); + paramIn(cp, "ptable.pointer", _basePtr); + } }; #endif // __MEM_MULTI_LEVEL_PAGE_TABLE_HH__ |