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.
28 * Authors: Alexandru Dutu
33 * Definitions of page table
39 #include "base/bitfield.hh"
40 #include "base/intmath.hh"
41 #include "base/trace.hh"
42 #include "config/the_isa.hh"
43 #include "debug/MMU.hh"
44 #include "mem/multi_level_page_table.hh"
45 #include "sim/faults.hh"
46 #include "sim/sim_object.hh"
49 using namespace TheISA;
51 template <class ISAOps>
52 MultiLevelPageTable<ISAOps>::MultiLevelPageTable(const std::string &__name,
53 uint64_t _pid, System *_sys)
54 : PageTableBase(__name, _pid), system(_sys),
55 logLevelSize(PageTableLayout),
56 numLevels(logLevelSize.size())
60 template <class ISAOps>
61 MultiLevelPageTable<ISAOps>::~MultiLevelPageTable()
65 template <class ISAOps>
67 MultiLevelPageTable<ISAOps>::initState(ThreadContext* tc)
69 basePtr = pTableISAOps.getBasePtr(tc);
70 if (basePtr == 0) basePtr++;
71 DPRINTF(MMU, "basePtr: %d\n", basePtr);
73 system->pagePtr = basePtr;
75 /* setting first level of the page table */
76 uint64_t log_req_size = floorLog2(sizeof(PageTableEntry)) +
77 logLevelSize[numLevels-1];
78 assert(log_req_size >= PageShift);
79 uint64_t npages = 1 << (log_req_size - PageShift);
81 Addr paddr = system->allocPhysPages(npages);
83 PortProxy &p = system->physProxy;
84 p.memsetBlob(paddr, 0, npages << PageShift);
88 template <class ISAOps>
90 MultiLevelPageTable<ISAOps>::walk(Addr vaddr, bool allocate, Addr &PTE_addr)
92 std::vector<uint64_t> offsets = pTableISAOps.getOffsets(vaddr);
94 Addr level_base = basePtr;
95 for (int i = numLevels - 1; i > 0; i--) {
97 Addr entry_addr = (level_base<<PageShift) +
98 offsets[i] * sizeof(PageTableEntry);
100 PortProxy &p = system->physProxy;
101 PageTableEntry entry = p.read<PageTableEntry>(entry_addr);
103 Addr next_entry_pnum = pTableISAOps.getPnum(entry);
104 if (next_entry_pnum == 0) {
106 if (!allocate) return false;
108 uint64_t log_req_size = floorLog2(sizeof(PageTableEntry)) +
110 assert(log_req_size >= PageShift);
111 uint64_t npages = 1 << (log_req_size - PageShift);
113 DPRINTF(MMU, "Allocating %d pages needed for entry in level %d\n",
116 /* allocate new entry */
117 Addr next_entry_paddr = system->allocPhysPages(npages);
118 p.memsetBlob(next_entry_paddr, 0, npages << PageShift);
120 next_entry_pnum = next_entry_paddr >> PageShift;
121 pTableISAOps.setPnum(entry, next_entry_pnum);
122 pTableISAOps.setPTEFields(entry);
123 p.write<PageTableEntry>(entry_addr, entry);
126 DPRINTF(MMU, "Level %d base: %d offset: %d entry: %d\n",
127 i, level_base, offsets[i], next_entry_pnum);
128 level_base = next_entry_pnum;
131 PTE_addr = (level_base<<PageShift) +
132 offsets[0] * sizeof(PageTableEntry);
133 DPRINTF(MMU, "Returning PTE_addr: %x\n", PTE_addr);
137 template <class ISAOps>
139 MultiLevelPageTable<ISAOps>::map(Addr vaddr, Addr paddr,
140 int64_t size, uint64_t flags)
142 bool clobber = flags & Clobber;
143 // starting address must be page aligned
144 assert(pageOffset(vaddr) == 0);
146 DPRINTF(MMU, "Allocating Page: %#x-%#x\n", vaddr, vaddr + size);
148 PortProxy &p = system->physProxy;
150 for (; size > 0; size -= pageSize, vaddr += pageSize, paddr += pageSize) {
152 if (walk(vaddr, true, PTE_addr)) {
153 PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr);
154 Addr entry_paddr = pTableISAOps.getPnum(PTE);
155 if (!clobber && entry_paddr != 0) {
156 fatal("addr 0x%x already mapped to %x", vaddr, entry_paddr);
158 pTableISAOps.setPnum(PTE, paddr >> PageShift);
159 uint64_t PTE_flags = 0;
160 if (flags & NotPresent)
161 PTE_flags |= TheISA::PTE_NotPresent;
162 if (flags & Uncacheable)
163 PTE_flags |= TheISA::PTE_Uncacheable;
164 if (flags & ReadOnly)
165 PTE_flags |= TheISA::PTE_ReadOnly;
166 pTableISAOps.setPTEFields(PTE, PTE_flags);
167 p.write<PageTableEntry>(PTE_addr, PTE);
168 DPRINTF(MMU, "New mapping: %#x-%#x\n", vaddr, paddr);
170 eraseCacheEntry(vaddr);
171 updateCache(vaddr, TlbEntry(pid, vaddr, paddr,
179 template <class ISAOps>
181 MultiLevelPageTable<ISAOps>::remap(Addr vaddr, int64_t size, Addr new_vaddr)
183 assert(pageOffset(vaddr) == 0);
184 assert(pageOffset(new_vaddr) == 0);
186 DPRINTF(MMU, "moving pages from vaddr %08p to %08p, size = %d\n", vaddr,
189 PortProxy &p = system->physProxy;
192 size -= pageSize, vaddr += pageSize, new_vaddr += pageSize)
195 if (walk(vaddr, false, PTE_addr)) {
196 PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr);
197 Addr paddr = pTableISAOps.getPnum(PTE);
200 fatal("Page fault while remapping");
202 /* unmapping vaddr */
203 pTableISAOps.setPnum(PTE, 0);
204 p.write<PageTableEntry>(PTE_addr, PTE);
206 /* maping new_vaddr */
208 walk(new_vaddr, true, new_PTE_addr);
209 PageTableEntry new_PTE = p.read<PageTableEntry>(new_PTE_addr);
211 pTableISAOps.setPnum(new_PTE, paddr>>PageShift);
212 pTableISAOps.setPTEFields(new_PTE);
213 p.write<PageTableEntry>(new_PTE_addr, new_PTE);
214 DPRINTF(MMU, "Remapping: %#x-%#x\n", vaddr, new_PTE_addr);
217 eraseCacheEntry(vaddr);
218 updateCache(new_vaddr, TlbEntry(pid, new_vaddr, paddr,
219 pTableISAOps.isUncacheable(PTE),
220 pTableISAOps.isReadOnly(PTE)));
222 fatal("Page fault while remapping");
227 template <class ISAOps>
229 MultiLevelPageTable<ISAOps>::unmap(Addr vaddr, int64_t size)
231 assert(pageOffset(vaddr) == 0);
233 DPRINTF(MMU, "Unmapping page: %#x-%#x\n", vaddr, vaddr+ size);
235 PortProxy &p = system->physProxy;
237 for (; size > 0; size -= pageSize, vaddr += pageSize) {
239 if (walk(vaddr, false, PTE_addr)) {
240 PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr);
241 Addr paddr = pTableISAOps.getPnum(PTE);
243 fatal("PageTable::allocate: address 0x%x not mapped", vaddr);
245 pTableISAOps.setPnum(PTE, 0);
246 p.write<PageTableEntry>(PTE_addr, PTE);
247 DPRINTF(MMU, "Unmapping: %#x\n", vaddr);
249 eraseCacheEntry(vaddr);
251 fatal("Page fault while unmapping");
257 template <class ISAOps>
259 MultiLevelPageTable<ISAOps>::isUnmapped(Addr vaddr, int64_t size)
261 // starting address must be page aligned
262 assert(pageOffset(vaddr) == 0);
263 PortProxy &p = system->physProxy;
265 for (; size > 0; size -= pageSize, vaddr += pageSize) {
267 if (walk(vaddr, false, PTE_addr)) {
268 PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr);
269 if (pTableISAOps.getPnum(PTE) != 0)
277 template <class ISAOps>
279 MultiLevelPageTable<ISAOps>::lookup(Addr vaddr, TlbEntry &entry)
281 Addr page_addr = pageAlign(vaddr);
283 if (pTableCache[0].valid && pTableCache[0].vaddr == page_addr) {
284 entry = pTableCache[0].entry;
287 if (pTableCache[1].valid && pTableCache[1].vaddr == page_addr) {
288 entry = pTableCache[1].entry;
291 if (pTableCache[2].valid && pTableCache[2].vaddr == page_addr) {
292 entry = pTableCache[2].entry;
296 DPRINTF(MMU, "lookup page_addr: %#x\n", page_addr);
298 if (walk(page_addr, false, PTE_addr)) {
299 PortProxy &p = system->physProxy;
300 PageTableEntry PTE = p.read<PageTableEntry>(PTE_addr);
301 Addr pnum = pTableISAOps.getPnum(PTE);
305 entry = TlbEntry(pid, vaddr, pnum << PageShift,
306 pTableISAOps.isUncacheable(PTE),
307 pTableISAOps.isReadOnly(PTE));
308 updateCache(page_addr, entry);
315 template <class ISAOps>
317 MultiLevelPageTable<ISAOps>::serialize(CheckpointOut &cp) const
319 /** Since, the page table is stored in system memory
320 * which is serialized separately, we will serialize
321 * just the base pointer
323 paramOut(cp, "ptable.pointer", basePtr);
326 template <class ISAOps>
328 MultiLevelPageTable<ISAOps>::unserialize(CheckpointIn &cp)
330 paramIn(cp, "ptable.pointer", basePtr);