diff options
author | Gabe Black <gabeblack@google.com> | 2018-01-04 00:30:38 -0800 |
---|---|---|
committer | Gabe Black <gabeblack@google.com> | 2018-01-17 23:02:06 +0000 |
commit | be5f4836188e49003be4b78b158f201820b570dc (patch) | |
tree | 83ae738da5e0b76ffa99150af9cf967b738d6cb6 | |
parent | 096cdd508d49c9572b4464cd7c394a6f586f489d (diff) | |
download | gem5-be5f4836188e49003be4b78b158f201820b570dc.tar.xz |
mem: Change the multilevel page table to inherit from FuncPageTable.
KVM looks up translations using the image of the page table in the
guest's memory, but we don't have to. By maintaining that image in
addition to rather than instead of maintaining an abstract copy makes
our lookups faster, and ironically avoids duplicate implementation.
Change-Id: I9ff4cae6f7cf4027c3738b75f74eae50dde2fda1
Reviewed-on: https://gem5-review.googlesource.com/7341
Reviewed-by: Brandon Potter <Brandon.Potter@amd.com>
Maintainer: Gabe Black <gabeblack@google.com>
-rw-r--r-- | src/mem/multi_level_page_table.hh | 7 | ||||
-rw-r--r-- | src/mem/multi_level_page_table_impl.hh | 213 |
2 files changed, 63 insertions, 157 deletions
diff --git a/src/mem/multi_level_page_table.hh b/src/mem/multi_level_page_table.hh index 0e079b730..952c2b068 100644 --- a/src/mem/multi_level_page_table.hh +++ b/src/mem/multi_level_page_table.hh @@ -100,7 +100,7 @@ class System; * @see MultiLevelPageTable */ template <class ISAOps> -class MultiLevelPageTable : public PageTableBase +class MultiLevelPageTable : public FuncPageTable { /** * ISA specific operations @@ -134,9 +134,8 @@ class MultiLevelPageTable : public PageTableBase * @param allocate Specifies whether memory should be allocated while * walking the page table * @return PTE_addr The address of the found PTE - * @retval true if the page table walk has succeded, false otherwhise */ - bool walk(Addr vaddr, bool allocate, Addr &PTE_addr); + void walk(Addr vaddr, bool allocate, Addr &PTE_addr); public: MultiLevelPageTable(const std::string &__name, uint64_t _pid, @@ -149,8 +148,6 @@ public: uint64_t flags = 0) override; void remap(Addr vaddr, int64_t size, Addr new_vaddr) override; void unmap(Addr vaddr, int64_t size) override; - bool isUnmapped(Addr vaddr, int64_t size) override; - bool lookup(Addr vaddr, TheISA::TlbEntry &entry) override; void serialize(CheckpointOut &cp) const override; void unserialize(CheckpointIn &cp) override; }; diff --git a/src/mem/multi_level_page_table_impl.hh b/src/mem/multi_level_page_table_impl.hh index ab7f0663f..702c08c0a 100644 --- a/src/mem/multi_level_page_table_impl.hh +++ b/src/mem/multi_level_page_table_impl.hh @@ -48,7 +48,7 @@ template <class ISAOps> MultiLevelPageTable<ISAOps>::MultiLevelPageTable(const std::string &__name, uint64_t _pid, System *_sys, Addr pageSize) - : PageTableBase(__name, _pid, pageSize), system(_sys), + : FuncPageTable(__name, _pid, pageSize), system(_sys), logLevelSize(PageTableLayout), numLevels(logLevelSize.size()) { @@ -64,7 +64,8 @@ void MultiLevelPageTable<ISAOps>::initState(ThreadContext* tc) { basePtr = pTableISAOps.getBasePtr(tc); - if (basePtr == 0) basePtr++; + if (basePtr == 0) + basePtr++; DPRINTF(MMU, "basePtr: %d\n", basePtr); system->pagePtr = basePtr; @@ -83,7 +84,7 @@ MultiLevelPageTable<ISAOps>::initState(ThreadContext* tc) template <class ISAOps> -bool +void MultiLevelPageTable<ISAOps>::walk(Addr vaddr, bool allocate, Addr &PTE_addr) { std::vector<uint64_t> offsets = pTableISAOps.getOffsets(vaddr); @@ -100,10 +101,10 @@ MultiLevelPageTable<ISAOps>::walk(Addr vaddr, bool allocate, Addr &PTE_addr) Addr next_entry_pnum = pTableISAOps.getPnum(entry); if (next_entry_pnum == 0) { - if (!allocate) return false; + fatal_if(!allocate, "Page fault while walking the page table."); uint64_t log_req_size = floorLog2(sizeof(PageTableEntry)) + - logLevelSize[i-1]; + logLevelSize[i - 1]; assert(log_req_size >= PageShift); uint64_t npages = 1 << (log_req_size - PageShift); @@ -125,10 +126,9 @@ MultiLevelPageTable<ISAOps>::walk(Addr vaddr, bool allocate, Addr &PTE_addr) level_base = next_entry_pnum; } - PTE_addr = (level_base<<PageShift) + + PTE_addr = (level_base << PageShift) + offsets[0] * sizeof(PageTableEntry); DPRINTF(MMU, "Returning PTE_addr: %x\n", PTE_addr); - return true; } template <class ISAOps> @@ -136,40 +136,28 @@ void MultiLevelPageTable<ISAOps>::map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags) { - bool clobber = flags & Clobber; - // starting address must be page aligned - assert(pageOffset(vaddr) == 0); - - DPRINTF(MMU, "Allocating Page: %#x-%#x\n", vaddr, vaddr + size); + FuncPageTable::map(vaddr, paddr, size, flags); PortProxy &p = system->physProxy; - for (; size > 0; size -= pageSize, vaddr += pageSize, paddr += pageSize) { + while (size > 0) { Addr PTE_addr; - if (walk(vaddr, true, PTE_addr)) { - PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr); - Addr entry_paddr = pTableISAOps.getPnum(PTE); - if (!clobber && entry_paddr != 0) { - fatal("addr 0x%x already mapped to %x", vaddr, entry_paddr); - } - pTableISAOps.setPnum(PTE, paddr >> PageShift); - uint64_t PTE_flags = 0; - if (flags & NotPresent) - PTE_flags |= TheISA::PTE_NotPresent; - if (flags & Uncacheable) - PTE_flags |= TheISA::PTE_Uncacheable; - if (flags & ReadOnly) - PTE_flags |= TheISA::PTE_ReadOnly; - pTableISAOps.setPTEFields(PTE, PTE_flags); - p.write<PageTableEntry>(PTE_addr, PTE); - DPRINTF(MMU, "New mapping: %#x-%#x\n", vaddr, paddr); - - delete eraseCacheEntry(vaddr); - delete updateCache(vaddr, new TlbEntry(pid, vaddr, paddr, - flags & Uncacheable, - flags & ReadOnly)); - } - + walk(vaddr, true, PTE_addr); + PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr); + pTableISAOps.setPnum(PTE, paddr >> PageShift); + uint64_t PTE_flags = 0; + if (flags & NotPresent) + PTE_flags |= TheISA::PTE_NotPresent; + if (flags & Uncacheable) + PTE_flags |= TheISA::PTE_Uncacheable; + if (flags & ReadOnly) + PTE_flags |= TheISA::PTE_ReadOnly; + pTableISAOps.setPTEFields(PTE, PTE_flags); + p.write<PageTableEntry>(PTE_addr, PTE); + DPRINTF(MMU, "New mapping: %#x-%#x\n", vaddr, paddr); + size -= pageSize; + vaddr += pageSize; + paddr += pageSize; } } @@ -177,48 +165,33 @@ template <class ISAOps> void MultiLevelPageTable<ISAOps>::remap(Addr vaddr, int64_t size, Addr new_vaddr) { - assert(pageOffset(vaddr) == 0); - assert(pageOffset(new_vaddr) == 0); - - DPRINTF(MMU, "moving pages from vaddr %08p to %08p, size = %d\n", vaddr, - new_vaddr, size); + FuncPageTable::remap(vaddr, size, new_vaddr); PortProxy &p = system->physProxy; - for (; size > 0; - size -= pageSize, vaddr += pageSize, new_vaddr += pageSize) - { + while (size > 0) { Addr PTE_addr; - if (walk(vaddr, false, PTE_addr)) { - PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr); - Addr paddr = pTableISAOps.getPnum(PTE); - - if (paddr == 0) { - fatal("Page fault while remapping"); - } else { - /* unmapping vaddr */ - pTableISAOps.setPnum(PTE, 0); - p.write<PageTableEntry>(PTE_addr, PTE); - - /* maping new_vaddr */ - Addr new_PTE_addr; - walk(new_vaddr, true, new_PTE_addr); - PageTableEntry new_PTE = p.read<PageTableEntry>(new_PTE_addr); - - pTableISAOps.setPnum(new_PTE, paddr>>PageShift); - pTableISAOps.setPTEFields(new_PTE); - p.write<PageTableEntry>(new_PTE_addr, new_PTE); - DPRINTF(MMU, "Remapping: %#x-%#x\n", vaddr, new_PTE_addr); - } - - delete eraseCacheEntry(vaddr); - delete updateCache(new_vaddr, - new TlbEntry(pid, new_vaddr, paddr, - pTableISAOps.isUncacheable(PTE), - pTableISAOps.isReadOnly(PTE))); - } else { - fatal("Page fault while remapping"); - } + walk(vaddr, false, PTE_addr); + PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr); + Addr paddr = pTableISAOps.getPnum(PTE); + + fatal_if(paddr == 0, "Page fault while remapping"); + /* unmapping vaddr */ + pTableISAOps.setPnum(PTE, 0); + p.write<PageTableEntry>(PTE_addr, PTE); + + /* maping new_vaddr */ + Addr new_PTE_addr; + walk(new_vaddr, true, new_PTE_addr); + PageTableEntry new_PTE = p.read<PageTableEntry>(new_PTE_addr); + + pTableISAOps.setPnum(new_PTE, paddr >> PageShift); + pTableISAOps.setPTEFields(new_PTE); + p.write<PageTableEntry>(new_PTE_addr, new_PTE); + DPRINTF(MMU, "Remapping: %#x-%#x\n", vaddr, new_PTE_addr); + size -= pageSize; + vaddr += pageSize; + new_vaddr += pageSize; } } @@ -226,95 +199,30 @@ template <class ISAOps> void MultiLevelPageTable<ISAOps>::unmap(Addr vaddr, int64_t size) { - assert(pageOffset(vaddr) == 0); - - DPRINTF(MMU, "Unmapping page: %#x-%#x\n", vaddr, vaddr+ size); - - PortProxy &p = system->physProxy; - - for (; size > 0; size -= pageSize, vaddr += pageSize) { - Addr PTE_addr; - if (walk(vaddr, false, PTE_addr)) { - PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr); - Addr paddr = pTableISAOps.getPnum(PTE); - if (paddr == 0) { - fatal("PageTable::allocate: address 0x%x not mapped", vaddr); - } else { - pTableISAOps.setPnum(PTE, 0); - p.write<PageTableEntry>(PTE_addr, PTE); - DPRINTF(MMU, "Unmapping: %#x\n", vaddr); - } - delete eraseCacheEntry(vaddr); - } else { - fatal("Page fault while unmapping"); - } - } - -} + FuncPageTable::unmap(vaddr, size); -template <class ISAOps> -bool -MultiLevelPageTable<ISAOps>::isUnmapped(Addr vaddr, int64_t size) -{ - // starting address must be page aligned - assert(pageOffset(vaddr) == 0); PortProxy &p = system->physProxy; - for (; size > 0; size -= pageSize, vaddr += pageSize) { + while (size > 0) { Addr PTE_addr; - if (walk(vaddr, false, PTE_addr)) { - PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr); - if (pTableISAOps.getPnum(PTE) != 0) - return false; - } - } - - return true; -} - -template <class ISAOps> -bool -MultiLevelPageTable<ISAOps>::lookup(Addr vaddr, TlbEntry &entry) -{ - Addr page_addr = pageAlign(vaddr); - - if (pTableCache[0].entry && pTableCache[0].vaddr == page_addr) { - entry = *pTableCache[0].entry; - return true; - } - if (pTableCache[1].entry && pTableCache[1].vaddr == page_addr) { - entry = *pTableCache[1].entry; - return true; - } - if (pTableCache[2].entry && pTableCache[2].vaddr == page_addr) { - entry = *pTableCache[2].entry; - return true; - } - - DPRINTF(MMU, "lookup page_addr: %#x\n", page_addr); - Addr PTE_addr; - if (walk(page_addr, false, PTE_addr)) { - PortProxy &p = system->physProxy; + walk(vaddr, false, PTE_addr); PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr); - Addr pnum = pTableISAOps.getPnum(PTE); - if (pnum == 0) - return false; - - TlbEntry *new_entry = new TlbEntry(pid, vaddr, pnum << PageShift, - pTableISAOps.isUncacheable(PTE), - pTableISAOps.isReadOnly(PTE)); - entry = *new_entry; - delete updateCache(page_addr, new_entry); - } else { - return false; + Addr paddr = pTableISAOps.getPnum(PTE); + fatal_if(paddr == 0, + "PageTable::allocate: address %#x not mapped", vaddr); + pTableISAOps.setPnum(PTE, 0); + p.write<PageTableEntry>(PTE_addr, PTE); + DPRINTF(MMU, "Unmapping: %#x\n", vaddr); + size -= pageSize; + vaddr += pageSize; } - return true; } template <class ISAOps> void MultiLevelPageTable<ISAOps>::serialize(CheckpointOut &cp) const { + FuncPageTable::serialize(cp); /** Since, the page table is stored in system memory * which is serialized separately, we will serialize * just the base pointer @@ -326,5 +234,6 @@ template <class ISAOps> void MultiLevelPageTable<ISAOps>::unserialize(CheckpointIn &cp) { + FuncPageTable::unserialize(cp); paramIn(cp, "ptable.pointer", basePtr); } |