pagetable_walker.cc (5897:29cecf4fe602) pagetable_walker.cc (5904:5c61233cbd53)
1/*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * The software must be used only for Non-Commercial Use which means any
10 * use which is NOT directed to receiving any direct monetary
11 * compensation for, or commercial advantage from such use. Illustrative
12 * examples of non-commercial use are academic research, personal study,
13 * teaching, education and corporate research & development.
14 * Illustrative examples of commercial use are distributing products for
15 * commercial advantage and providing services using the software for
16 * commercial advantage.
17 *
18 * If you wish to use this software or functionality therein that may be
19 * covered by patents for commercial use, please contact:
20 * Director of Intellectual Property Licensing
21 * Office of Strategy and Technology
22 * Hewlett-Packard Company
23 * 1501 Page Mill Road
24 * Palo Alto, California 94304
25 *
26 * Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer. Redistributions
28 * in binary form must reproduce the above copyright notice, this list of
29 * conditions and the following disclaimer in the documentation and/or
30 * other materials provided with the distribution. Neither the name of
31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission. No right of
34 * sublicense is granted herewith. Derivatives of the software and
35 * output created using the software may be prepared, but only for
36 * Non-Commercial Uses. Derivatives of the software may be shared with
37 * others provided: (i) the others agree to abide by the list of
38 * conditions herein which includes the Non-Commercial Use restrictions;
39 * and (ii) such Derivatives of the software include the above copyright
40 * notice to acknowledge the contribution from this software where
41 * applicable, this list of conditions and the disclaimer below.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * Authors: Gabe Black
56 */
57
58#include "arch/x86/pagetable.hh"
59#include "arch/x86/pagetable_walker.hh"
60#include "arch/x86/tlb.hh"
61#include "base/bitfield.hh"
62#include "cpu/thread_context.hh"
63#include "cpu/base.hh"
64#include "mem/packet_access.hh"
65#include "mem/request.hh"
66#include "sim/system.hh"
67
68namespace X86ISA {
69
70// Unfortunately, the placement of the base field in a page table entry is
71// very erratic and would make a mess here. It might be moved here at some
72// point in the future.
73BitUnion64(PageTableEntry)
74 Bitfield<63> nx;
75 Bitfield<11, 9> avl;
76 Bitfield<8> g;
77 Bitfield<7> ps;
78 Bitfield<6> d;
79 Bitfield<5> a;
80 Bitfield<4> pcd;
81 Bitfield<3> pwt;
82 Bitfield<2> u;
83 Bitfield<1> w;
84 Bitfield<0> p;
85EndBitUnion(PageTableEntry)
86
87Fault
88Walker::doNext(PacketPtr &write)
89{
90 assert(state != Ready && state != Waiting);
91 write = NULL;
92 PageTableEntry pte;
93 if (size == 8)
94 pte = read->get<uint64_t>();
95 else
96 pte = read->get<uint32_t>();
97 VAddr vaddr = entry.vaddr;
98 bool uncacheable = pte.pcd;
99 Addr nextRead = 0;
100 bool doWrite = false;
101 bool badNX = pte.nx && (!tlb->allowNX() || !enableNX);
102 switch(state) {
103 case LongPML4:
1/*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * The software must be used only for Non-Commercial Use which means any
10 * use which is NOT directed to receiving any direct monetary
11 * compensation for, or commercial advantage from such use. Illustrative
12 * examples of non-commercial use are academic research, personal study,
13 * teaching, education and corporate research & development.
14 * Illustrative examples of commercial use are distributing products for
15 * commercial advantage and providing services using the software for
16 * commercial advantage.
17 *
18 * If you wish to use this software or functionality therein that may be
19 * covered by patents for commercial use, please contact:
20 * Director of Intellectual Property Licensing
21 * Office of Strategy and Technology
22 * Hewlett-Packard Company
23 * 1501 Page Mill Road
24 * Palo Alto, California 94304
25 *
26 * Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer. Redistributions
28 * in binary form must reproduce the above copyright notice, this list of
29 * conditions and the following disclaimer in the documentation and/or
30 * other materials provided with the distribution. Neither the name of
31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission. No right of
34 * sublicense is granted herewith. Derivatives of the software and
35 * output created using the software may be prepared, but only for
36 * Non-Commercial Uses. Derivatives of the software may be shared with
37 * others provided: (i) the others agree to abide by the list of
38 * conditions herein which includes the Non-Commercial Use restrictions;
39 * and (ii) such Derivatives of the software include the above copyright
40 * notice to acknowledge the contribution from this software where
41 * applicable, this list of conditions and the disclaimer below.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * Authors: Gabe Black
56 */
57
58#include "arch/x86/pagetable.hh"
59#include "arch/x86/pagetable_walker.hh"
60#include "arch/x86/tlb.hh"
61#include "base/bitfield.hh"
62#include "cpu/thread_context.hh"
63#include "cpu/base.hh"
64#include "mem/packet_access.hh"
65#include "mem/request.hh"
66#include "sim/system.hh"
67
68namespace X86ISA {
69
70// Unfortunately, the placement of the base field in a page table entry is
71// very erratic and would make a mess here. It might be moved here at some
72// point in the future.
73BitUnion64(PageTableEntry)
74 Bitfield<63> nx;
75 Bitfield<11, 9> avl;
76 Bitfield<8> g;
77 Bitfield<7> ps;
78 Bitfield<6> d;
79 Bitfield<5> a;
80 Bitfield<4> pcd;
81 Bitfield<3> pwt;
82 Bitfield<2> u;
83 Bitfield<1> w;
84 Bitfield<0> p;
85EndBitUnion(PageTableEntry)
86
87Fault
88Walker::doNext(PacketPtr &write)
89{
90 assert(state != Ready && state != Waiting);
91 write = NULL;
92 PageTableEntry pte;
93 if (size == 8)
94 pte = read->get<uint64_t>();
95 else
96 pte = read->get<uint32_t>();
97 VAddr vaddr = entry.vaddr;
98 bool uncacheable = pte.pcd;
99 Addr nextRead = 0;
100 bool doWrite = false;
101 bool badNX = pte.nx && (!tlb->allowNX() || !enableNX);
102 switch(state) {
103 case LongPML4:
104 DPRINTF(PageTableWalker,
105 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte);
104 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size;
105 doWrite = !pte.a;
106 pte.a = 1;
107 entry.writable = pte.w;
108 entry.user = pte.u;
109 if (badNX || !pte.p) {
110 stop();
111 return pageFault(pte.p);
112 }
113 entry.noExec = pte.nx;
114 nextState = LongPDP;
115 break;
116 case LongPDP:
106 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size;
107 doWrite = !pte.a;
108 pte.a = 1;
109 entry.writable = pte.w;
110 entry.user = pte.u;
111 if (badNX || !pte.p) {
112 stop();
113 return pageFault(pte.p);
114 }
115 entry.noExec = pte.nx;
116 nextState = LongPDP;
117 break;
118 case LongPDP:
119 DPRINTF(PageTableWalker,
120 "Got long mode PDP entry %#016x.\n", (uint64_t)pte);
117 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size;
118 doWrite = !pte.a;
119 pte.a = 1;
120 entry.writable = entry.writable && pte.w;
121 entry.user = entry.user && pte.u;
122 if (badNX || !pte.p) {
123 stop();
124 return pageFault(pte.p);
125 }
126 nextState = LongPD;
127 break;
128 case LongPD:
121 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size;
122 doWrite = !pte.a;
123 pte.a = 1;
124 entry.writable = entry.writable && pte.w;
125 entry.user = entry.user && pte.u;
126 if (badNX || !pte.p) {
127 stop();
128 return pageFault(pte.p);
129 }
130 nextState = LongPD;
131 break;
132 case LongPD:
133 DPRINTF(PageTableWalker,
134 "Got long mode PD entry %#016x.\n", (uint64_t)pte);
129 doWrite = !pte.a;
130 pte.a = 1;
131 entry.writable = entry.writable && pte.w;
132 entry.user = entry.user && pte.u;
133 if (badNX || !pte.p) {
134 stop();
135 return pageFault(pte.p);
136 }
137 if (!pte.ps) {
138 // 4 KB page
139 entry.size = 4 * (1 << 10);
140 nextRead =
141 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size;
142 nextState = LongPTE;
143 break;
144 } else {
145 // 2 MB page
146 entry.size = 2 * (1 << 20);
147 entry.paddr = (uint64_t)pte & (mask(31) << 21);
148 entry.uncacheable = uncacheable;
149 entry.global = pte.g;
150 entry.patBit = bits(pte, 12);
151 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
152 tlb->insert(entry.vaddr, entry);
153 stop();
154 return NoFault;
155 }
156 case LongPTE:
135 doWrite = !pte.a;
136 pte.a = 1;
137 entry.writable = entry.writable && pte.w;
138 entry.user = entry.user && pte.u;
139 if (badNX || !pte.p) {
140 stop();
141 return pageFault(pte.p);
142 }
143 if (!pte.ps) {
144 // 4 KB page
145 entry.size = 4 * (1 << 10);
146 nextRead =
147 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size;
148 nextState = LongPTE;
149 break;
150 } else {
151 // 2 MB page
152 entry.size = 2 * (1 << 20);
153 entry.paddr = (uint64_t)pte & (mask(31) << 21);
154 entry.uncacheable = uncacheable;
155 entry.global = pte.g;
156 entry.patBit = bits(pte, 12);
157 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
158 tlb->insert(entry.vaddr, entry);
159 stop();
160 return NoFault;
161 }
162 case LongPTE:
163 DPRINTF(PageTableWalker,
164 "Got long mode PTE entry %#016x.\n", (uint64_t)pte);
157 doWrite = !pte.a;
158 pte.a = 1;
159 entry.writable = entry.writable && pte.w;
160 entry.user = entry.user && pte.u;
161 if (badNX || !pte.p) {
162 stop();
163 return pageFault(pte.p);
164 }
165 entry.paddr = (uint64_t)pte & (mask(40) << 12);
166 entry.uncacheable = uncacheable;
167 entry.global = pte.g;
168 entry.patBit = bits(pte, 12);
169 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
170 tlb->insert(entry.vaddr, entry);
171 stop();
172 return NoFault;
173 case PAEPDP:
165 doWrite = !pte.a;
166 pte.a = 1;
167 entry.writable = entry.writable && pte.w;
168 entry.user = entry.user && pte.u;
169 if (badNX || !pte.p) {
170 stop();
171 return pageFault(pte.p);
172 }
173 entry.paddr = (uint64_t)pte & (mask(40) << 12);
174 entry.uncacheable = uncacheable;
175 entry.global = pte.g;
176 entry.patBit = bits(pte, 12);
177 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
178 tlb->insert(entry.vaddr, entry);
179 stop();
180 return NoFault;
181 case PAEPDP:
182 DPRINTF(PageTableWalker,
183 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte);
174 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
175 if (!pte.p) {
176 stop();
177 return pageFault(pte.p);
178 }
179 nextState = PAEPD;
180 break;
181 case PAEPD:
184 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
185 if (!pte.p) {
186 stop();
187 return pageFault(pte.p);
188 }
189 nextState = PAEPD;
190 break;
191 case PAEPD:
192 DPRINTF(PageTableWalker,
193 "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte);
182 doWrite = !pte.a;
183 pte.a = 1;
184 entry.writable = pte.w;
185 entry.user = pte.u;
186 if (badNX || !pte.p) {
187 stop();
188 return pageFault(pte.p);
189 }
190 if (!pte.ps) {
191 // 4 KB page
192 entry.size = 4 * (1 << 10);
193 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
194 nextState = PAEPTE;
195 break;
196 } else {
197 // 2 MB page
198 entry.size = 2 * (1 << 20);
199 entry.paddr = (uint64_t)pte & (mask(31) << 21);
200 entry.uncacheable = uncacheable;
201 entry.global = pte.g;
202 entry.patBit = bits(pte, 12);
203 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
204 tlb->insert(entry.vaddr, entry);
205 stop();
206 return NoFault;
207 }
208 case PAEPTE:
194 doWrite = !pte.a;
195 pte.a = 1;
196 entry.writable = pte.w;
197 entry.user = pte.u;
198 if (badNX || !pte.p) {
199 stop();
200 return pageFault(pte.p);
201 }
202 if (!pte.ps) {
203 // 4 KB page
204 entry.size = 4 * (1 << 10);
205 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
206 nextState = PAEPTE;
207 break;
208 } else {
209 // 2 MB page
210 entry.size = 2 * (1 << 20);
211 entry.paddr = (uint64_t)pte & (mask(31) << 21);
212 entry.uncacheable = uncacheable;
213 entry.global = pte.g;
214 entry.patBit = bits(pte, 12);
215 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
216 tlb->insert(entry.vaddr, entry);
217 stop();
218 return NoFault;
219 }
220 case PAEPTE:
221 DPRINTF(PageTableWalker,
222 "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte);
209 doWrite = !pte.a;
210 pte.a = 1;
211 entry.writable = entry.writable && pte.w;
212 entry.user = entry.user && pte.u;
213 if (badNX || !pte.p) {
214 stop();
215 return pageFault(pte.p);
216 }
217 entry.paddr = (uint64_t)pte & (mask(40) << 12);
218 entry.uncacheable = uncacheable;
219 entry.global = pte.g;
220 entry.patBit = bits(pte, 7);
221 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
222 tlb->insert(entry.vaddr, entry);
223 stop();
224 return NoFault;
225 case PSEPD:
223 doWrite = !pte.a;
224 pte.a = 1;
225 entry.writable = entry.writable && pte.w;
226 entry.user = entry.user && pte.u;
227 if (badNX || !pte.p) {
228 stop();
229 return pageFault(pte.p);
230 }
231 entry.paddr = (uint64_t)pte & (mask(40) << 12);
232 entry.uncacheable = uncacheable;
233 entry.global = pte.g;
234 entry.patBit = bits(pte, 7);
235 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
236 tlb->insert(entry.vaddr, entry);
237 stop();
238 return NoFault;
239 case PSEPD:
240 DPRINTF(PageTableWalker,
241 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte);
226 doWrite = !pte.a;
227 pte.a = 1;
228 entry.writable = pte.w;
229 entry.user = pte.u;
230 if (!pte.p) {
231 stop();
232 return pageFault(pte.p);
233 }
234 if (!pte.ps) {
235 // 4 KB page
236 entry.size = 4 * (1 << 10);
237 nextRead =
238 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
239 nextState = PTE;
240 break;
241 } else {
242 // 4 MB page
243 entry.size = 4 * (1 << 20);
244 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
245 entry.uncacheable = uncacheable;
246 entry.global = pte.g;
247 entry.patBit = bits(pte, 12);
248 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
249 tlb->insert(entry.vaddr, entry);
250 stop();
251 return NoFault;
252 }
253 case PD:
242 doWrite = !pte.a;
243 pte.a = 1;
244 entry.writable = pte.w;
245 entry.user = pte.u;
246 if (!pte.p) {
247 stop();
248 return pageFault(pte.p);
249 }
250 if (!pte.ps) {
251 // 4 KB page
252 entry.size = 4 * (1 << 10);
253 nextRead =
254 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
255 nextState = PTE;
256 break;
257 } else {
258 // 4 MB page
259 entry.size = 4 * (1 << 20);
260 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
261 entry.uncacheable = uncacheable;
262 entry.global = pte.g;
263 entry.patBit = bits(pte, 12);
264 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
265 tlb->insert(entry.vaddr, entry);
266 stop();
267 return NoFault;
268 }
269 case PD:
270 DPRINTF(PageTableWalker,
271 "Got legacy mode PD entry %#08x.\n", (uint32_t)pte);
254 doWrite = !pte.a;
255 pte.a = 1;
256 entry.writable = pte.w;
257 entry.user = pte.u;
258 if (!pte.p) {
259 stop();
260 return pageFault(pte.p);
261 }
262 // 4 KB page
263 entry.size = 4 * (1 << 10);
264 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
265 nextState = PTE;
266 break;
267 case PTE:
272 doWrite = !pte.a;
273 pte.a = 1;
274 entry.writable = pte.w;
275 entry.user = pte.u;
276 if (!pte.p) {
277 stop();
278 return pageFault(pte.p);
279 }
280 // 4 KB page
281 entry.size = 4 * (1 << 10);
282 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
283 nextState = PTE;
284 break;
285 case PTE:
286 DPRINTF(PageTableWalker,
287 "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte);
268 doWrite = !pte.a;
269 pte.a = 1;
270 entry.writable = pte.w;
271 entry.user = pte.u;
272 if (!pte.p) {
273 stop();
274 return pageFault(pte.p);
275 }
276 entry.paddr = (uint64_t)pte & (mask(20) << 12);
277 entry.uncacheable = uncacheable;
278 entry.global = pte.g;
279 entry.patBit = bits(pte, 7);
280 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
281 tlb->insert(entry.vaddr, entry);
282 stop();
283 return NoFault;
284 default:
285 panic("Unknown page table walker state %d!\n");
286 }
287 PacketPtr oldRead = read;
288 //If we didn't return, we're setting up another read.
289 Request::Flags flags = oldRead->req->getFlags();
290 flags.set(Request::UNCACHEABLE, uncacheable);
291 RequestPtr request =
292 new Request(nextRead, oldRead->getSize(), flags);
293 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
294 read->allocate();
295 //If we need to write, adjust the read packet to write the modified value
296 //back to memory.
297 if (doWrite) {
298 write = oldRead;
299 write->set<uint64_t>(pte);
300 write->cmd = MemCmd::WriteReq;
301 write->setDest(Packet::Broadcast);
302 } else {
303 write = NULL;
304 delete oldRead->req;
305 delete oldRead;
306 }
307 return NoFault;
308}
309
310Fault
311Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
312 RequestPtr _req, bool _write, bool _execute)
313{
314 assert(state == Ready);
315 tc = _tc;
316 req = _req;
317 Addr vaddr = req->getVaddr();
318 execute = _execute;
319 write = _write;
320 translation = _translation;
321
322 VAddr addr = vaddr;
323
324 //Figure out what we're doing.
325 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
326 Addr top = 0;
327 // Check if we're in long mode or not
328 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
329 size = 8;
330 if (efer.lma) {
331 // Do long mode.
332 state = LongPML4;
333 top = (cr3.longPdtb << 12) + addr.longl4 * size;
334 enableNX = efer.nxe;
335 } else {
336 // We're in some flavor of legacy mode.
337 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
338 if (cr4.pae) {
339 // Do legacy PAE.
340 state = PAEPDP;
341 top = (cr3.paePdtb << 5) + addr.pael3 * size;
342 enableNX = efer.nxe;
343 } else {
344 size = 4;
345 top = (cr3.pdtb << 12) + addr.norml2 * size;
346 if (cr4.pse) {
347 // Do legacy PSE.
348 state = PSEPD;
349 } else {
350 // Do legacy non PSE.
351 state = PD;
352 }
353 enableNX = false;
354 }
355 }
356
357 nextState = Ready;
358 entry.vaddr = vaddr;
359
360 Request::Flags flags = Request::PHYSICAL;
361 if (cr3.pcd)
362 flags.set(Request::UNCACHEABLE);
363 RequestPtr request = new Request(top, size, flags);
364 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
365 read->allocate();
366 Enums::MemoryMode memMode = sys->getMemoryMode();
367 if (memMode == Enums::timing) {
368 nextState = state;
369 state = Waiting;
370 timingFault = NoFault;
371 sendPackets();
372 } else if (memMode == Enums::atomic) {
373 Fault fault;
374 do {
375 port.sendAtomic(read);
376 PacketPtr write = NULL;
377 fault = doNext(write);
378 assert(fault == NoFault || read == NULL);
379 state = nextState;
380 nextState = Ready;
381 if (write)
382 port.sendAtomic(write);
383 } while(read);
384 state = Ready;
385 nextState = Waiting;
386 return fault;
387 } else {
388 panic("Unrecognized memory system mode.\n");
389 }
390 return NoFault;
391}
392
393bool
394Walker::WalkerPort::recvTiming(PacketPtr pkt)
395{
396 return walker->recvTiming(pkt);
397}
398
399bool
400Walker::recvTiming(PacketPtr pkt)
401{
402 if (pkt->isResponse() && !pkt->wasNacked()) {
403 assert(inflight);
404 assert(state == Waiting);
405 assert(!read);
406 inflight--;
407 if (pkt->isRead()) {
408 state = nextState;
409 nextState = Ready;
410 PacketPtr write = NULL;
411 read = pkt;
412 timingFault = doNext(write);
413 state = Waiting;
414 assert(timingFault == NoFault || read == NULL);
415 if (write) {
416 writes.push_back(write);
417 }
418 sendPackets();
419 } else {
420 sendPackets();
421 }
422 if (inflight == 0 && read == NULL && writes.size() == 0) {
423 state = Ready;
424 nextState = Waiting;
425 if (timingFault == NoFault) {
426 /*
427 * Finish the translation. Now that we now the right entry is
428 * in the TLB, this should work with no memory accesses.
429 * There could be new faults unrelated to the table walk like
430 * permissions violations, so we'll need the return value as
431 * well.
432 */
433 bool delayedResponse;
434 Fault fault = tlb->translate(req, tc, NULL, write, execute,
435 delayedResponse, true);
436 assert(!delayedResponse);
437 // Let the CPU continue.
438 translation->finish(fault, req, tc, write);
439 } else {
440 // There was a fault during the walk. Let the CPU know.
441 translation->finish(timingFault, req, tc, write);
442 }
443 }
444 } else if (pkt->wasNacked()) {
445 pkt->reinitNacked();
446 if (!port.sendTiming(pkt)) {
447 inflight--;
448 retrying = true;
449 if (pkt->isWrite()) {
450 writes.push_back(pkt);
451 } else {
452 assert(!read);
453 read = pkt;
454 }
455 }
456 }
457 return true;
458}
459
460Tick
461Walker::WalkerPort::recvAtomic(PacketPtr pkt)
462{
463 return 0;
464}
465
466void
467Walker::WalkerPort::recvFunctional(PacketPtr pkt)
468{
469 return;
470}
471
472void
473Walker::WalkerPort::recvStatusChange(Status status)
474{
475 if (status == RangeChange) {
476 if (!snoopRangeSent) {
477 snoopRangeSent = true;
478 sendStatusChange(Port::RangeChange);
479 }
480 return;
481 }
482
483 panic("Unexpected recvStatusChange.\n");
484}
485
486void
487Walker::WalkerPort::recvRetry()
488{
489 walker->recvRetry();
490}
491
492void
493Walker::recvRetry()
494{
495 retrying = false;
496 sendPackets();
497}
498
499void
500Walker::sendPackets()
501{
502 //If we're already waiting for the port to become available, just return.
503 if (retrying)
504 return;
505
506 //Reads always have priority
507 if (read) {
508 PacketPtr pkt = read;
509 read = NULL;
510 inflight++;
511 if (!port.sendTiming(pkt)) {
512 retrying = true;
513 read = pkt;
514 inflight--;
515 return;
516 }
517 }
518 //Send off as many of the writes as we can.
519 while (writes.size()) {
520 PacketPtr write = writes.back();
521 writes.pop_back();
522 inflight++;
523 if (!port.sendTiming(write)) {
524 retrying = true;
525 writes.push_back(write);
526 inflight--;
527 return;
528 }
529 }
530}
531
532Port *
533Walker::getPort(const std::string &if_name, int idx)
534{
535 if (if_name == "port")
536 return &port;
537 else
538 panic("No page table walker port named %s!\n", if_name);
539}
540
541Fault
542Walker::pageFault(bool present)
543{
288 doWrite = !pte.a;
289 pte.a = 1;
290 entry.writable = pte.w;
291 entry.user = pte.u;
292 if (!pte.p) {
293 stop();
294 return pageFault(pte.p);
295 }
296 entry.paddr = (uint64_t)pte & (mask(20) << 12);
297 entry.uncacheable = uncacheable;
298 entry.global = pte.g;
299 entry.patBit = bits(pte, 7);
300 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
301 tlb->insert(entry.vaddr, entry);
302 stop();
303 return NoFault;
304 default:
305 panic("Unknown page table walker state %d!\n");
306 }
307 PacketPtr oldRead = read;
308 //If we didn't return, we're setting up another read.
309 Request::Flags flags = oldRead->req->getFlags();
310 flags.set(Request::UNCACHEABLE, uncacheable);
311 RequestPtr request =
312 new Request(nextRead, oldRead->getSize(), flags);
313 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
314 read->allocate();
315 //If we need to write, adjust the read packet to write the modified value
316 //back to memory.
317 if (doWrite) {
318 write = oldRead;
319 write->set<uint64_t>(pte);
320 write->cmd = MemCmd::WriteReq;
321 write->setDest(Packet::Broadcast);
322 } else {
323 write = NULL;
324 delete oldRead->req;
325 delete oldRead;
326 }
327 return NoFault;
328}
329
330Fault
331Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
332 RequestPtr _req, bool _write, bool _execute)
333{
334 assert(state == Ready);
335 tc = _tc;
336 req = _req;
337 Addr vaddr = req->getVaddr();
338 execute = _execute;
339 write = _write;
340 translation = _translation;
341
342 VAddr addr = vaddr;
343
344 //Figure out what we're doing.
345 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
346 Addr top = 0;
347 // Check if we're in long mode or not
348 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
349 size = 8;
350 if (efer.lma) {
351 // Do long mode.
352 state = LongPML4;
353 top = (cr3.longPdtb << 12) + addr.longl4 * size;
354 enableNX = efer.nxe;
355 } else {
356 // We're in some flavor of legacy mode.
357 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
358 if (cr4.pae) {
359 // Do legacy PAE.
360 state = PAEPDP;
361 top = (cr3.paePdtb << 5) + addr.pael3 * size;
362 enableNX = efer.nxe;
363 } else {
364 size = 4;
365 top = (cr3.pdtb << 12) + addr.norml2 * size;
366 if (cr4.pse) {
367 // Do legacy PSE.
368 state = PSEPD;
369 } else {
370 // Do legacy non PSE.
371 state = PD;
372 }
373 enableNX = false;
374 }
375 }
376
377 nextState = Ready;
378 entry.vaddr = vaddr;
379
380 Request::Flags flags = Request::PHYSICAL;
381 if (cr3.pcd)
382 flags.set(Request::UNCACHEABLE);
383 RequestPtr request = new Request(top, size, flags);
384 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
385 read->allocate();
386 Enums::MemoryMode memMode = sys->getMemoryMode();
387 if (memMode == Enums::timing) {
388 nextState = state;
389 state = Waiting;
390 timingFault = NoFault;
391 sendPackets();
392 } else if (memMode == Enums::atomic) {
393 Fault fault;
394 do {
395 port.sendAtomic(read);
396 PacketPtr write = NULL;
397 fault = doNext(write);
398 assert(fault == NoFault || read == NULL);
399 state = nextState;
400 nextState = Ready;
401 if (write)
402 port.sendAtomic(write);
403 } while(read);
404 state = Ready;
405 nextState = Waiting;
406 return fault;
407 } else {
408 panic("Unrecognized memory system mode.\n");
409 }
410 return NoFault;
411}
412
413bool
414Walker::WalkerPort::recvTiming(PacketPtr pkt)
415{
416 return walker->recvTiming(pkt);
417}
418
419bool
420Walker::recvTiming(PacketPtr pkt)
421{
422 if (pkt->isResponse() && !pkt->wasNacked()) {
423 assert(inflight);
424 assert(state == Waiting);
425 assert(!read);
426 inflight--;
427 if (pkt->isRead()) {
428 state = nextState;
429 nextState = Ready;
430 PacketPtr write = NULL;
431 read = pkt;
432 timingFault = doNext(write);
433 state = Waiting;
434 assert(timingFault == NoFault || read == NULL);
435 if (write) {
436 writes.push_back(write);
437 }
438 sendPackets();
439 } else {
440 sendPackets();
441 }
442 if (inflight == 0 && read == NULL && writes.size() == 0) {
443 state = Ready;
444 nextState = Waiting;
445 if (timingFault == NoFault) {
446 /*
447 * Finish the translation. Now that we now the right entry is
448 * in the TLB, this should work with no memory accesses.
449 * There could be new faults unrelated to the table walk like
450 * permissions violations, so we'll need the return value as
451 * well.
452 */
453 bool delayedResponse;
454 Fault fault = tlb->translate(req, tc, NULL, write, execute,
455 delayedResponse, true);
456 assert(!delayedResponse);
457 // Let the CPU continue.
458 translation->finish(fault, req, tc, write);
459 } else {
460 // There was a fault during the walk. Let the CPU know.
461 translation->finish(timingFault, req, tc, write);
462 }
463 }
464 } else if (pkt->wasNacked()) {
465 pkt->reinitNacked();
466 if (!port.sendTiming(pkt)) {
467 inflight--;
468 retrying = true;
469 if (pkt->isWrite()) {
470 writes.push_back(pkt);
471 } else {
472 assert(!read);
473 read = pkt;
474 }
475 }
476 }
477 return true;
478}
479
480Tick
481Walker::WalkerPort::recvAtomic(PacketPtr pkt)
482{
483 return 0;
484}
485
486void
487Walker::WalkerPort::recvFunctional(PacketPtr pkt)
488{
489 return;
490}
491
492void
493Walker::WalkerPort::recvStatusChange(Status status)
494{
495 if (status == RangeChange) {
496 if (!snoopRangeSent) {
497 snoopRangeSent = true;
498 sendStatusChange(Port::RangeChange);
499 }
500 return;
501 }
502
503 panic("Unexpected recvStatusChange.\n");
504}
505
506void
507Walker::WalkerPort::recvRetry()
508{
509 walker->recvRetry();
510}
511
512void
513Walker::recvRetry()
514{
515 retrying = false;
516 sendPackets();
517}
518
519void
520Walker::sendPackets()
521{
522 //If we're already waiting for the port to become available, just return.
523 if (retrying)
524 return;
525
526 //Reads always have priority
527 if (read) {
528 PacketPtr pkt = read;
529 read = NULL;
530 inflight++;
531 if (!port.sendTiming(pkt)) {
532 retrying = true;
533 read = pkt;
534 inflight--;
535 return;
536 }
537 }
538 //Send off as many of the writes as we can.
539 while (writes.size()) {
540 PacketPtr write = writes.back();
541 writes.pop_back();
542 inflight++;
543 if (!port.sendTiming(write)) {
544 retrying = true;
545 writes.push_back(write);
546 inflight--;
547 return;
548 }
549 }
550}
551
552Port *
553Walker::getPort(const std::string &if_name, int idx)
554{
555 if (if_name == "port")
556 return &port;
557 else
558 panic("No page table walker port named %s!\n", if_name);
559}
560
561Fault
562Walker::pageFault(bool present)
563{
564 DPRINTF(PageTableWalker, "Raising page fault.\n");
544 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
545 return new PageFault(entry.vaddr, present, write,
546 m5reg.cpl == 3, false, execute && enableNX);
547}
548
549}
550
551X86ISA::Walker *
552X86PagetableWalkerParams::create()
553{
554 return new X86ISA::Walker(this);
555}
565 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
566 return new PageFault(entry.vaddr, present, write,
567 m5reg.cpl == 3, false, execute && enableNX);
568}
569
570}
571
572X86ISA::Walker *
573X86PagetableWalkerParams::create()
574{
575 return new X86ISA::Walker(this);
576}