2 * Copyright (c) 2014 Advanced Micro Devices, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * Declaration of a multi-level page table.
34 #ifndef __MEM_MULTI_LEVEL_PAGE_TABLE_HH__
35 #define __MEM_MULTI_LEVEL_PAGE_TABLE_HH__
39 #include "base/types.hh"
40 #include "mem/page_table.hh"
41 #include "sim/system.hh"
44 * This class implements an in-memory multi-level page table that can be
45 * configured to follow ISA specifications. It can be used instead of the
46 * PageTable class in SE mode to allow CPU models (e.g. X86KvmCPU)
47 * to do a normal page table walk.
49 * To reduce memory required to store the page table, a multi-level page
50 * table stores its translations similarly with a radix tree. Let n be
51 * the number of levels and {Ln, Ln-1, ..., L1, L0} a set that specifies
52 * the number of entries for each level as base 2 logarithm values. A
53 * multi-level page table will store its translations at level 0 (the
54 * leaves of the tree) and it will be layed out in memory in the
57 * +------------------------------+
58 * level n |Ln-1_E0|Ln-1_E1|...|Ln-1_E2^Ln|
59 * +------------------------------+
61 * +------------------------+ +------------------------+
62 * level n-1 |Ln-2_E0|...|Ln-2_E2^Ln-1| |Ln-2_E0|...|Ln-2_E2^Ln-1|
63 * +------------------------+ +------------------------+
69 * +------------------+ +------------+ +------------+
70 * level 1 |L0_E1|...|L0_E2^L1| |...|L0_E2^L1| ... |...|L0_E2^L1|
71 * +------------------+ +------------+ +------------+
73 * +------------------------------+
74 * |Lk-1_E0|Lk-1_E1|...|Lk-1_E2^Lk|
75 * +------------------------------+
76 * is a level k entry that holds 2^Lk entries in Lk-1 level.
78 * Essentially, a level n entry will contain 2^Ln level n-1 entries,
79 * a level n-1 entry will hold 2^Ln-1 level n-2 entries etc.
81 * The virtual address is split into offsets that index into the
82 * different levels of the page table.
84 * +--------------------------------+
85 * |LnOffset|...|L1Offset|PageOffset|
86 * +--------------------------------+
88 * For example L0Offset will be formed by the bits in range
89 * [log2(PageOffset), log2(PageOffset)+L0].
91 * For every level of the page table, from n to 1, the base address
92 * of the entry is loaded, the offset in the virtual address for
93 * that particular level is used to index into the entry which
94 * will reveal the memory address of the entry in the next level.
96 * @see MultiLevelPageTable
101 template <class First, class ...Rest>
103 prepTopTable(System *system, Addr pageSize)
105 Addr addr = system->allocPhysPages(First::tableSize());
106 PortProxy &p = system->physProxy;
107 p.memsetBlob(addr, 0, First::tableSize() * pageSize);
111 template <class ...Types>
114 template <class First, class Second, class ...Rest>
115 struct LastType<First, Second, Rest...>
117 typedef typename LastType<Second, Rest...>::type type;
120 template <class Only>
121 struct LastType<Only>
127 template <class ...Types>
130 template <class Final, class Only>
131 struct WalkWrapper<Final, Only>
134 walk(System *system, Addr pageSize, Addr table, Addr vaddr,
135 bool allocate, Final *entry)
137 entry->read(system->physProxy, table, vaddr);
141 template <class Final, class First, class Second, class ...Rest>
142 struct WalkWrapper<Final, First, Second, Rest...>
145 walk(System *system, Addr pageSize, Addr table, Addr vaddr,
146 bool allocate, Final *entry)
149 first.read(system->physProxy, table, vaddr);
152 if (!first.present()) {
154 "Page fault while walking the page table.");
155 next = prepTopTable<Second>(system, pageSize);
157 first.write(system->physProxy);
159 next = first.paddr();
161 WalkWrapper<Final, Second, Rest...>::walk(
162 system, pageSize, next, vaddr, allocate, entry);
166 template <class ...EntryTypes>
168 walk(System *system, Addr pageSize, Addr table, Addr vaddr,
169 bool allocate, typename LastType<EntryTypes...>::type *entry)
171 WalkWrapper<typename LastType<EntryTypes...>::type, EntryTypes...>::walk(
172 system, pageSize, table, vaddr, allocate, entry);
178 template <class ...EntryTypes>
179 class MultiLevelPageTable : public EmulationPageTable
181 typedef typename LastType<EntryTypes...>::type Final;
184 * Pointer to System object
189 * Physical address to the last level of the page table
194 MultiLevelPageTable(const std::string &__name, uint64_t _pid,
195 System *_sys, Addr _pageSize) :
196 EmulationPageTable(__name, _pid, _pageSize), system(_sys)
199 ~MultiLevelPageTable() {}
207 _basePtr = prepTopTable<EntryTypes...>(system, _pageSize);
210 Addr basePtr() { return _basePtr; }
213 map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags = 0) override
215 EmulationPageTable::map(vaddr, paddr, size, flags);
219 for (int64_t offset = 0; offset < size; offset += _pageSize) {
220 walk<EntryTypes...>(system, _pageSize, _basePtr,
221 vaddr + offset, true, &entry);
223 entry.reset(paddr + offset, true, flags & Uncacheable,
225 entry.write(system->physProxy);
227 DPRINTF(MMU, "New mapping: %#x-%#x\n",
228 vaddr + offset, paddr + offset);
233 remap(Addr vaddr, int64_t size, Addr new_vaddr) override
235 EmulationPageTable::remap(vaddr, size, new_vaddr);
237 Final old_entry, new_entry;
239 for (int64_t offset = 0; offset < size; offset += _pageSize) {
240 // Unmap the original mapping.
241 walk<EntryTypes...>(system, _pageSize, _basePtr, vaddr + offset,
243 old_entry.present(false);
244 old_entry.write(system->physProxy);
247 walk<EntryTypes...>(system, _pageSize, _basePtr,
248 new_vaddr + offset, true, &new_entry);
249 new_entry.reset(old_entry.paddr(), true, old_entry.uncacheable(),
250 old_entry.readonly());
251 new_entry.write(system->physProxy);
256 unmap(Addr vaddr, int64_t size) override
258 EmulationPageTable::unmap(vaddr, size);
262 for (int64_t offset = 0; offset < size; offset += _pageSize) {
263 walk<EntryTypes...>(system, _pageSize, _basePtr,
264 vaddr + offset, false, &entry);
265 fatal_if(!entry.present(),
266 "PageTable::unmap: Address %#x not mapped.", vaddr);
267 entry.present(false);
268 entry.write(system->physProxy);
269 DPRINTF(MMU, "Unmapping: %#x\n", vaddr);
274 serialize(CheckpointOut &cp) const override
276 EmulationPageTable::serialize(cp);
277 /** Since, the page table is stored in system memory
278 * which is serialized separately, we will serialize
279 * just the base pointer
281 paramOut(cp, "ptable.pointer", _basePtr);
285 unserialize(CheckpointIn &cp) override
287 EmulationPageTable::unserialize(cp);
288 paramIn(cp, "ptable.pointer", _basePtr);
291 #endif // __MEM_MULTI_LEVEL_PAGE_TABLE_HH__