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>
This commit is contained in:
Gabe Black
2018-01-08 04:41:25 -08:00
parent 8cb6bb444a
commit db8c55dede
10 changed files with 264 additions and 404 deletions

View File

@@ -63,39 +63,6 @@ typedef Trie<Addr, X86ISA::TlbEntry> TlbEntryTrie;
namespace X86ISA
{
BitUnion64(VAddr)
Bitfield<20, 12> longl1;
Bitfield<29, 21> longl2;
Bitfield<38, 30> longl3;
Bitfield<47, 39> longl4;
Bitfield<20, 12> pael1;
Bitfield<29, 21> pael2;
Bitfield<31, 30> pael3;
Bitfield<21, 12> norml1;
Bitfield<31, 22> norml2;
EndBitUnion(VAddr)
// Unfortunately, the placement of the base field in a page table entry is
// very erratic and would make a mess here. It might be moved here at some
// point in the future.
BitUnion64(PageTableEntry)
Bitfield<63> nx;
Bitfield<51, 12> base;
Bitfield<11, 9> avl;
Bitfield<8> g;
Bitfield<7> ps;
Bitfield<6> d;
Bitfield<5> a;
Bitfield<4> pcd;
Bitfield<3> pwt;
Bitfield<2> u;
Bitfield<1> w;
Bitfield<0> p;
EndBitUnion(PageTableEntry)
struct TlbEntry : public Serializable
{
// The base of the physical page.
@@ -152,65 +119,87 @@ namespace X86ISA
void unserialize(CheckpointIn &cp) override;
};
/** The size of each level of the page table expressed in base 2
* logarithmic values
*/
const std::vector<uint8_t> PageTableLayout = {9, 9, 9, 9};
/* x86 specific PTE flags */
enum PTEField{
PTE_NotPresent = 1,
PTE_Supervisor = 2,
PTE_ReadOnly = 4,
PTE_Uncacheable = 8,
};
BitUnion64(VAddr)
Bitfield<20, 12> longl1;
Bitfield<29, 21> longl2;
Bitfield<38, 30> longl3;
Bitfield<47, 39> longl4;
/** Page table operations specific to x86 ISA.
* Indended to be used as parameter of MultiLevelPageTable.
*/
class PageTableOps
Bitfield<20, 12> pael1;
Bitfield<29, 21> pael2;
Bitfield<31, 30> pael3;
Bitfield<21, 12> norml1;
Bitfield<31, 22> norml2;
EndBitUnion(VAddr)
// Unfortunately, the placement of the base field in a page table entry is
// very erratic and would make a mess here. It might be moved here at some
// point in the future.
BitUnion64(PageTableEntry)
Bitfield<63> nx;
Bitfield<51, 12> base;
Bitfield<11, 9> avl;
Bitfield<8> g;
Bitfield<7> ps;
Bitfield<6> d;
Bitfield<5> a;
Bitfield<4> pcd;
Bitfield<3> pwt;
Bitfield<2> u;
Bitfield<1> w;
Bitfield<0> p;
EndBitUnion(PageTableEntry)
template <int first, int last>
class LongModePTE
{
public:
void setPTEFields(PageTableEntry& PTE, uint64_t flags = 0)
Addr paddr() { return pte.base << PageShift; }
void paddr(Addr addr) { pte.base = addr >> PageShift; }
bool present() { return pte.p; }
void present(bool p) { pte.p = p ? 1 : 0; }
bool uncacheable() { return pte.pcd; }
void uncacheable(bool u) { pte.pcd = u ? 1 : 0; }
bool readonly() { return !pte.w; }
void readonly(bool r) { pte.w = r ? 0 : 1; }
void
read(PortProxy &p, Addr table, Addr vaddr)
{
PTE.p = flags & PTE_NotPresent ? 0 : 1;
PTE.pcd = flags & PTE_Uncacheable ? 1 : 0;
PTE.w = flags & PTE_ReadOnly ? 0 : 1;
PTE.u = flags & PTE_Supervisor ? 0 : 1;
entryAddr = table;
entryAddr += bits(vaddr, first, last) * sizeof(PageTableEntry);
pte = p.read<PageTableEntry>(entryAddr);
}
/** returns the page number out of a page table entry */
Addr getPnum(PageTableEntry PTE)
void
reset(Addr _paddr, bool _present=true,
bool _uncacheable=false, bool _readonly=false)
{
return PTE.base;
pte = 0;
pte.u = 1;
paddr(_paddr);
present(_present);
uncacheable(_uncacheable);
readonly(_readonly);
};
void write(PortProxy &p) { p.write(entryAddr, pte); }
static int
tableSize()
{
return 1 << ((first - last) + 4 - PageShift);
}
bool isUncacheable(const PageTableEntry PTE)
{
return PTE.pcd;
}
bool isReadOnly(PageTableEntry PTE)
{
return !PTE.w;
}
/** sets the page number in a page table entry */
void setPnum(PageTableEntry& PTE, Addr paddr)
{
PTE.base = paddr;
}
/** returns the offsets to index in every level of a page
* table, contained in a virtual address
*/
std::vector<uint64_t> getOffsets(Addr vaddr)
{
X86ISA::VAddr addr(vaddr);
return {addr.longl1, addr.longl2, addr.longl3, addr.longl4};
}
protected:
PageTableEntry pte;
Addr entryAddr;
};
}
#endif

View File

@@ -96,14 +96,21 @@ static const int ArgumentReg32[] = {
static const int NumArgumentRegs32 M5_VAR_USED =
sizeof(ArgumentReg) / sizeof(const int);
template class MultiLevelPageTable<LongModePTE<47, 39>,
LongModePTE<38, 30>,
LongModePTE<29, 21>,
LongModePTE<20, 12> >;
typedef MultiLevelPageTable<LongModePTE<47, 39>,
LongModePTE<38, 30>,
LongModePTE<29, 21>,
LongModePTE<20, 12> > ArchPageTable;
X86Process::X86Process(ProcessParams *params, ObjectFile *objFile,
SyscallDesc *_syscallDescs, int _numSyscallDescs)
: Process(params, params->useArchPT ?
static_cast<EmulationPageTable *>(
new ArchPageTable(
params->name, params->pid,
params->system, PageBytes,
PageTableLayout)) :
new ArchPageTable(params->name, params->pid,
params->system, PageBytes)) :
new EmulationPageTable(params->name, params->pid,
PageBytes),
objFile),
@@ -543,23 +550,22 @@ X86_64Process::initState()
physProxy.writeBlob(pfHandlerPhysAddr, faultBlob, sizeof(faultBlob));
MultiLevelPageTable<PageTableOps> *pt =
dynamic_cast<MultiLevelPageTable<PageTableOps> *>(pTable);
/* Syscall handler */
pt->map(syscallCodeVirtAddr, syscallCodePhysAddr, PageBytes, false);
pTable->map(syscallCodeVirtAddr, syscallCodePhysAddr,
PageBytes, false);
/* GDT */
pt->map(GDTVirtAddr, gdtPhysAddr, PageBytes, false);
pTable->map(GDTVirtAddr, gdtPhysAddr, PageBytes, false);
/* IDT */
pt->map(IDTVirtAddr, idtPhysAddr, PageBytes, false);
pTable->map(IDTVirtAddr, idtPhysAddr, PageBytes, false);
/* TSS */
pt->map(TSSVirtAddr, tssPhysAddr, PageBytes, false);
pTable->map(TSSVirtAddr, tssPhysAddr, PageBytes, false);
/* IST */
pt->map(ISTVirtAddr, istPhysAddr, PageBytes, false);
pTable->map(ISTVirtAddr, istPhysAddr, PageBytes, false);
/* PF handler */
pt->map(PFHandlerVirtAddr, pfHandlerPhysAddr, PageBytes, false);
pTable->map(PFHandlerVirtAddr, pfHandlerPhysAddr, PageBytes, false);
/* MMIO region for m5ops */
pt->map(MMIORegionVirtAddr, MMIORegionPhysAddr, 16*PageBytes, false);
pTable->map(MMIORegionVirtAddr, MMIORegionPhysAddr,
16 * PageBytes, false);
} else {
for (int i = 0; i < contextIds.size(); i++) {
ThreadContext * tc = system->getThreadContext(contextIds[i]);

View File

@@ -43,6 +43,7 @@
#include <string>
#include <vector>
#include "arch/x86/pagetable.hh"
#include "mem/multi_level_page_table.hh"
#include "sim/aux_vector.hh"
#include "sim/process.hh"
@@ -65,7 +66,6 @@ namespace X86ISA
* These page tables are stored in system memory and respect x86
* specification.
*/
typedef MultiLevelPageTable<PageTableOps> ArchPageTable;
Addr _gdtStart;
Addr _gdtSize;