multi_level_page_table.hh revision 13867
110298Salexandru.dutu@amd.com/* 210298Salexandru.dutu@amd.com * Copyright (c) 2014 Advanced Micro Devices, Inc. 310298Salexandru.dutu@amd.com * All rights reserved. 410298Salexandru.dutu@amd.com * 510298Salexandru.dutu@amd.com * Redistribution and use in source and binary forms, with or without 610298Salexandru.dutu@amd.com * modification, are permitted provided that the following conditions are 710298Salexandru.dutu@amd.com * met: redistributions of source code must retain the above copyright 810298Salexandru.dutu@amd.com * notice, this list of conditions and the following disclaimer; 910298Salexandru.dutu@amd.com * redistributions in binary form must reproduce the above copyright 1010298Salexandru.dutu@amd.com * notice, this list of conditions and the following disclaimer in the 1110298Salexandru.dutu@amd.com * documentation and/or other materials provided with the distribution; 1210298Salexandru.dutu@amd.com * neither the name of the copyright holders nor the names of its 1310298Salexandru.dutu@amd.com * contributors may be used to endorse or promote products derived from 1410298Salexandru.dutu@amd.com * this software without specific prior written permission. 1510298Salexandru.dutu@amd.com * 1610298Salexandru.dutu@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1710298Salexandru.dutu@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1810298Salexandru.dutu@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1910298Salexandru.dutu@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2010298Salexandru.dutu@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2110298Salexandru.dutu@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210298Salexandru.dutu@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2310298Salexandru.dutu@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2410298Salexandru.dutu@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2510298Salexandru.dutu@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2610298Salexandru.dutu@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2710298Salexandru.dutu@amd.com * 2810298Salexandru.dutu@amd.com * Authors: Alexandru Dutu 2910298Salexandru.dutu@amd.com */ 3010298Salexandru.dutu@amd.com 3110298Salexandru.dutu@amd.com/** 3210298Salexandru.dutu@amd.com * @file 3310298Salexandru.dutu@amd.com * Declaration of a multi-level page table. 3410298Salexandru.dutu@amd.com */ 3510298Salexandru.dutu@amd.com 3610298Salexandru.dutu@amd.com#ifndef __MEM_MULTI_LEVEL_PAGE_TABLE_HH__ 3710298Salexandru.dutu@amd.com#define __MEM_MULTI_LEVEL_PAGE_TABLE_HH__ 3810298Salexandru.dutu@amd.com 3910298Salexandru.dutu@amd.com#include <string> 4010298Salexandru.dutu@amd.com 4110298Salexandru.dutu@amd.com#include "base/types.hh" 4210298Salexandru.dutu@amd.com#include "mem/page_table.hh" 4311800Sbrandon.potter@amd.com 4411800Sbrandon.potter@amd.comclass System; 4510298Salexandru.dutu@amd.com 4610298Salexandru.dutu@amd.com/** 4710298Salexandru.dutu@amd.com * This class implements an in-memory multi-level page table that can be 4810298Salexandru.dutu@amd.com * configured to follow ISA specifications. It can be used instead of the 4910298Salexandru.dutu@amd.com * PageTable class in SE mode to allow CPU models (e.g. X86KvmCPU) 5010298Salexandru.dutu@amd.com * to do a normal page table walk. 5110298Salexandru.dutu@amd.com * 5210298Salexandru.dutu@amd.com * To reduce memory required to store the page table, a multi-level page 5310298Salexandru.dutu@amd.com * table stores its translations similarly with a radix tree. Let n be 5410298Salexandru.dutu@amd.com * the number of levels and {Ln, Ln-1, ..., L1, L0} a set that specifies 5510298Salexandru.dutu@amd.com * the number of entries for each level as base 2 logarithm values. A 5610298Salexandru.dutu@amd.com * multi-level page table will store its translations at level 0 (the 5710298Salexandru.dutu@amd.com * leaves of the tree) and it will be layed out in memory in the 5810298Salexandru.dutu@amd.com * following way: 5910298Salexandru.dutu@amd.com * 6010298Salexandru.dutu@amd.com * +------------------------------+ 6110298Salexandru.dutu@amd.com * level n |Ln-1_E0|Ln-1_E1|...|Ln-1_E2^Ln| 6210298Salexandru.dutu@amd.com * +------------------------------+ 6310298Salexandru.dutu@amd.com * / \ 6410298Salexandru.dutu@amd.com * +------------------------+ +------------------------+ 6510298Salexandru.dutu@amd.com * level n-1 |Ln-2_E0|...|Ln-2_E2^Ln-1| |Ln-2_E0|...|Ln-2_E2^Ln-1| 6610298Salexandru.dutu@amd.com * +------------------------+ +------------------------+ 6710298Salexandru.dutu@amd.com * / \ / \ 6810298Salexandru.dutu@amd.com * . 6910298Salexandru.dutu@amd.com * . 7010298Salexandru.dutu@amd.com * . 7110298Salexandru.dutu@amd.com * / / \ 7210298Salexandru.dutu@amd.com * +------------------+ +------------+ +------------+ 7310298Salexandru.dutu@amd.com * level 1 |L0_E1|...|L0_E2^L1| |...|L0_E2^L1| ... |...|L0_E2^L1| 7410298Salexandru.dutu@amd.com * +------------------+ +------------+ +------------+ 7510298Salexandru.dutu@amd.com * , where 7610298Salexandru.dutu@amd.com * +------------------------------+ 7710298Salexandru.dutu@amd.com * |Lk-1_E0|Lk-1_E1|...|Lk-1_E2^Lk| 7810298Salexandru.dutu@amd.com * +------------------------------+ 7910298Salexandru.dutu@amd.com * is a level k entry that holds 2^Lk entries in Lk-1 level. 8010298Salexandru.dutu@amd.com * 8110298Salexandru.dutu@amd.com * Essentially, a level n entry will contain 2^Ln level n-1 entries, 8210298Salexandru.dutu@amd.com * a level n-1 entry will hold 2^Ln-1 level n-2 entries etc. 8310298Salexandru.dutu@amd.com * 8410298Salexandru.dutu@amd.com * The virtual address is split into offsets that index into the 8510298Salexandru.dutu@amd.com * different levels of the page table. 8610298Salexandru.dutu@amd.com * 8710298Salexandru.dutu@amd.com * +--------------------------------+ 8810298Salexandru.dutu@amd.com * |LnOffset|...|L1Offset|PageOffset| 8910298Salexandru.dutu@amd.com * +--------------------------------+ 9010298Salexandru.dutu@amd.com * 9110298Salexandru.dutu@amd.com * For example L0Offset will be formed by the bits in range 9210298Salexandru.dutu@amd.com * [log2(PageOffset), log2(PageOffset)+L0]. 9310298Salexandru.dutu@amd.com * 9410298Salexandru.dutu@amd.com * For every level of the page table, from n to 1, the base address 9510298Salexandru.dutu@amd.com * of the entry is loaded, the offset in the virtual address for 9610298Salexandru.dutu@amd.com * that particular level is used to index into the entry which 9710298Salexandru.dutu@amd.com * will reveal the memory address of the entry in the next level. 9810298Salexandru.dutu@amd.com * 9910298Salexandru.dutu@amd.com * @see MultiLevelPageTable 10010298Salexandru.dutu@amd.com */ 10112460Sgabeblack@google.com 10212460Sgabeblack@google.comnamespace { 10312460Sgabeblack@google.com 10412460Sgabeblack@google.comtemplate <class First, class ...Rest> 10512460Sgabeblack@google.comAddr 10612460Sgabeblack@google.comprepTopTable(System *system, Addr pageSize) 10712460Sgabeblack@google.com{ 10812460Sgabeblack@google.com Addr addr = system->allocPhysPages(First::tableSize()); 10912460Sgabeblack@google.com PortProxy &p = system->physProxy; 11012460Sgabeblack@google.com p.memsetBlob(addr, 0, First::tableSize() * pageSize); 11112460Sgabeblack@google.com return addr; 11212460Sgabeblack@google.com} 11312460Sgabeblack@google.com 11412460Sgabeblack@google.comtemplate <class ...Types> 11512460Sgabeblack@google.comstruct LastType; 11612460Sgabeblack@google.com 11712460Sgabeblack@google.comtemplate <class First, class Second, class ...Rest> 11812460Sgabeblack@google.comstruct LastType<First, Second, Rest...> 11912460Sgabeblack@google.com{ 12012460Sgabeblack@google.com typedef typename LastType<Second, Rest...>::type type; 12112460Sgabeblack@google.com}; 12212460Sgabeblack@google.com 12312460Sgabeblack@google.comtemplate <class Only> 12412460Sgabeblack@google.comstruct LastType<Only> 12512460Sgabeblack@google.com{ 12612460Sgabeblack@google.com typedef Only type; 12712460Sgabeblack@google.com}; 12812460Sgabeblack@google.com 12912460Sgabeblack@google.com 13012460Sgabeblack@google.comtemplate <class ...Types> 13112460Sgabeblack@google.comstruct WalkWrapper; 13212460Sgabeblack@google.com 13312460Sgabeblack@google.comtemplate <class Final, class Only> 13412460Sgabeblack@google.comstruct WalkWrapper<Final, Only> 13512460Sgabeblack@google.com{ 13612460Sgabeblack@google.com static void 13712460Sgabeblack@google.com walk(System *system, Addr pageSize, Addr table, Addr vaddr, 13812460Sgabeblack@google.com bool allocate, Final *entry) 13912460Sgabeblack@google.com { 14012460Sgabeblack@google.com entry->read(system->physProxy, table, vaddr); 14112460Sgabeblack@google.com } 14212460Sgabeblack@google.com}; 14312460Sgabeblack@google.com 14412460Sgabeblack@google.comtemplate <class Final, class First, class Second, class ...Rest> 14512460Sgabeblack@google.comstruct WalkWrapper<Final, First, Second, Rest...> 14612460Sgabeblack@google.com{ 14712460Sgabeblack@google.com static void 14812460Sgabeblack@google.com walk(System *system, Addr pageSize, Addr table, Addr vaddr, 14912460Sgabeblack@google.com bool allocate, Final *entry) 15012460Sgabeblack@google.com { 15112460Sgabeblack@google.com First first; 15212460Sgabeblack@google.com first.read(system->physProxy, table, vaddr); 15312460Sgabeblack@google.com 15412460Sgabeblack@google.com Addr next; 15512460Sgabeblack@google.com if (!first.present()) { 15612460Sgabeblack@google.com fatal_if(!allocate, 15712460Sgabeblack@google.com "Page fault while walking the page table."); 15812460Sgabeblack@google.com next = prepTopTable<Second>(system, pageSize); 15912460Sgabeblack@google.com first.reset(next); 16012460Sgabeblack@google.com first.write(system->physProxy); 16112460Sgabeblack@google.com } else { 16212460Sgabeblack@google.com next = first.paddr(); 16312460Sgabeblack@google.com } 16412460Sgabeblack@google.com WalkWrapper<Final, Second, Rest...>::walk( 16512460Sgabeblack@google.com system, pageSize, next, vaddr, allocate, entry); 16612460Sgabeblack@google.com } 16712460Sgabeblack@google.com}; 16812460Sgabeblack@google.com 16912460Sgabeblack@google.comtemplate <class ...EntryTypes> 17012460Sgabeblack@google.comvoid 17112460Sgabeblack@google.comwalk(System *system, Addr pageSize, Addr table, Addr vaddr, 17212460Sgabeblack@google.com bool allocate, typename LastType<EntryTypes...>::type *entry) 17312460Sgabeblack@google.com{ 17412460Sgabeblack@google.com WalkWrapper<typename LastType<EntryTypes...>::type, EntryTypes...>::walk( 17512460Sgabeblack@google.com system, pageSize, table, vaddr, allocate, entry); 17612460Sgabeblack@google.com} 17712460Sgabeblack@google.com 17812460Sgabeblack@google.com} 17912460Sgabeblack@google.com 18012460Sgabeblack@google.com 18112460Sgabeblack@google.comtemplate <class ...EntryTypes> 18212448Sgabeblack@google.comclass MultiLevelPageTable : public EmulationPageTable 18310298Salexandru.dutu@amd.com{ 18412460Sgabeblack@google.com typedef typename LastType<EntryTypes...>::type Final; 18510298Salexandru.dutu@amd.com 18610298Salexandru.dutu@amd.com /** 18710298Salexandru.dutu@amd.com * Pointer to System object 18810298Salexandru.dutu@amd.com */ 18910298Salexandru.dutu@amd.com System *system; 19010298Salexandru.dutu@amd.com 19110298Salexandru.dutu@amd.com /** 19210298Salexandru.dutu@amd.com * Physical address to the last level of the page table 19310298Salexandru.dutu@amd.com */ 19412458Sgabeblack@google.com Addr _basePtr; 19510298Salexandru.dutu@amd.com 19610298Salexandru.dutu@amd.compublic: 19710556Salexandru.dutu@amd.com MultiLevelPageTable(const std::string &__name, uint64_t _pid, 19812460Sgabeblack@google.com System *_sys, Addr pageSize) : 19912460Sgabeblack@google.com EmulationPageTable(__name, _pid, pageSize), system(_sys) 20012460Sgabeblack@google.com {} 20110298Salexandru.dutu@amd.com 20212460Sgabeblack@google.com ~MultiLevelPageTable() {} 20312460Sgabeblack@google.com 20412460Sgabeblack@google.com void 20512460Sgabeblack@google.com initState(ThreadContext* tc) override 20612460Sgabeblack@google.com { 20713867Salexandru.dutu@amd.com if (shared) 20813867Salexandru.dutu@amd.com return; 20913867Salexandru.dutu@amd.com 21012460Sgabeblack@google.com _basePtr = prepTopTable<EntryTypes...>(system, pageSize); 21112460Sgabeblack@google.com } 21210298Salexandru.dutu@amd.com 21312458Sgabeblack@google.com Addr basePtr() { return _basePtr; } 21412458Sgabeblack@google.com 21512460Sgabeblack@google.com void 21612460Sgabeblack@google.com map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags = 0) override 21712460Sgabeblack@google.com { 21812460Sgabeblack@google.com EmulationPageTable::map(vaddr, paddr, size, flags); 21912460Sgabeblack@google.com 22012460Sgabeblack@google.com Final entry; 22112460Sgabeblack@google.com 22212460Sgabeblack@google.com for (int64_t offset = 0; offset < size; offset += pageSize) { 22312460Sgabeblack@google.com walk<EntryTypes...>(system, pageSize, _basePtr, 22412460Sgabeblack@google.com vaddr + offset, true, &entry); 22512460Sgabeblack@google.com 22612460Sgabeblack@google.com entry.reset(paddr + offset, true, flags & Uncacheable, 22712460Sgabeblack@google.com flags & ReadOnly); 22812460Sgabeblack@google.com entry.write(system->physProxy); 22912460Sgabeblack@google.com 23012460Sgabeblack@google.com DPRINTF(MMU, "New mapping: %#x-%#x\n", 23112460Sgabeblack@google.com vaddr + offset, paddr + offset); 23212460Sgabeblack@google.com } 23312460Sgabeblack@google.com } 23412460Sgabeblack@google.com 23512460Sgabeblack@google.com void 23612460Sgabeblack@google.com remap(Addr vaddr, int64_t size, Addr new_vaddr) override 23712460Sgabeblack@google.com { 23812460Sgabeblack@google.com EmulationPageTable::remap(vaddr, size, new_vaddr); 23912460Sgabeblack@google.com 24012460Sgabeblack@google.com Final old_entry, new_entry; 24112460Sgabeblack@google.com 24212460Sgabeblack@google.com for (int64_t offset = 0; offset < size; offset += pageSize) { 24312460Sgabeblack@google.com // Unmap the original mapping. 24412460Sgabeblack@google.com walk<EntryTypes...>(system, pageSize, _basePtr, vaddr + offset, 24512460Sgabeblack@google.com false, &old_entry); 24612460Sgabeblack@google.com old_entry.present(false); 24712460Sgabeblack@google.com old_entry.write(system->physProxy); 24812460Sgabeblack@google.com 24912460Sgabeblack@google.com // Map the new one. 25012460Sgabeblack@google.com walk<EntryTypes...>(system, pageSize, _basePtr, new_vaddr + offset, 25112460Sgabeblack@google.com true, &new_entry); 25212460Sgabeblack@google.com new_entry.reset(old_entry.paddr(), true, old_entry.uncacheable(), 25312460Sgabeblack@google.com old_entry.readonly()); 25412460Sgabeblack@google.com new_entry.write(system->physProxy); 25512460Sgabeblack@google.com } 25612460Sgabeblack@google.com } 25712460Sgabeblack@google.com 25812460Sgabeblack@google.com void 25912460Sgabeblack@google.com unmap(Addr vaddr, int64_t size) override 26012460Sgabeblack@google.com { 26112460Sgabeblack@google.com EmulationPageTable::unmap(vaddr, size); 26212460Sgabeblack@google.com 26312460Sgabeblack@google.com Final entry; 26412460Sgabeblack@google.com 26512460Sgabeblack@google.com for (int64_t offset = 0; offset < size; offset += pageSize) { 26612460Sgabeblack@google.com walk<EntryTypes...>(system, pageSize, _basePtr, 26712460Sgabeblack@google.com vaddr + offset, false, &entry); 26812460Sgabeblack@google.com fatal_if(!entry.present(), 26912460Sgabeblack@google.com "PageTable::unmap: Address %#x not mapped.", vaddr); 27012460Sgabeblack@google.com entry.present(false); 27112460Sgabeblack@google.com entry.write(system->physProxy); 27212460Sgabeblack@google.com DPRINTF(MMU, "Unmapping: %#x\n", vaddr); 27312460Sgabeblack@google.com } 27412460Sgabeblack@google.com } 27512460Sgabeblack@google.com 27612460Sgabeblack@google.com void 27712460Sgabeblack@google.com serialize(CheckpointOut &cp) const override 27812460Sgabeblack@google.com { 27912460Sgabeblack@google.com EmulationPageTable::serialize(cp); 28012460Sgabeblack@google.com /** Since, the page table is stored in system memory 28112460Sgabeblack@google.com * which is serialized separately, we will serialize 28212460Sgabeblack@google.com * just the base pointer 28312460Sgabeblack@google.com */ 28412460Sgabeblack@google.com paramOut(cp, "ptable.pointer", _basePtr); 28512460Sgabeblack@google.com } 28612460Sgabeblack@google.com 28712460Sgabeblack@google.com void 28812460Sgabeblack@google.com unserialize(CheckpointIn &cp) override 28912460Sgabeblack@google.com { 29012460Sgabeblack@google.com EmulationPageTable::unserialize(cp); 29112460Sgabeblack@google.com paramIn(cp, "ptable.pointer", _basePtr); 29212460Sgabeblack@google.com } 29310298Salexandru.dutu@amd.com}; 29410298Salexandru.dutu@amd.com#endif // __MEM_MULTI_LEVEL_PAGE_TABLE_HH__ 295