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:
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user