pagetable_walker.cc (5736:426510e758ad) pagetable_walker.cc (5881:73c0aaaaf186)
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
87void
88Walker::doNext(PacketPtr &read, 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 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)
110 panic("NX violation!\n");
111 entry.noExec = pte.nx;
112 if (!pte.p)
113 panic("Page at %#x not present!\n", entry.vaddr);
114 nextState = LongPDP;
115 break;
116 case LongPDP:
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)
123 panic("NX violation!\n");
124 if (!pte.p)
125 panic("Page at %#x not present!\n", entry.vaddr);
126 nextState = LongPD;
127 break;
128 case LongPD:
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)
134 panic("NX violation!\n");
135 if (!pte.p)
136 panic("Page at %#x not present!\n", entry.vaddr);
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 nextState = Ready;
154 delete read->req;
155 delete read;
156 read = NULL;
157 return;
158 }
159 case LongPTE:
160 doWrite = !pte.a;
161 pte.a = 1;
162 entry.writable = entry.writable && pte.w;
163 entry.user = entry.user && pte.u;
164 if (badNX)
165 panic("NX violation!\n");
166 if (!pte.p)
167 panic("Page at %#x not present!\n", entry.vaddr);
168 entry.paddr = (uint64_t)pte & (mask(40) << 12);
169 entry.uncacheable = uncacheable;
170 entry.global = pte.g;
171 entry.patBit = bits(pte, 12);
172 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
173 tlb->insert(entry.vaddr, entry);
174 nextState = Ready;
175 delete read->req;
176 delete read;
177 read = NULL;
178 return;
179 case PAEPDP:
180 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
181 if (!pte.p)
182 panic("Page at %#x not present!\n", entry.vaddr);
183 nextState = PAEPD;
184 break;
185 case PAEPD:
186 doWrite = !pte.a;
187 pte.a = 1;
188 entry.writable = pte.w;
189 entry.user = pte.u;
190 if (badNX)
191 panic("NX violation!\n");
192 if (!pte.p)
193 panic("Page at %#x not present!\n", entry.vaddr);
194 if (!pte.ps) {
195 // 4 KB page
196 entry.size = 4 * (1 << 10);
197 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
198 nextState = PAEPTE;
199 break;
200 } else {
201 // 2 MB page
202 entry.size = 2 * (1 << 20);
203 entry.paddr = (uint64_t)pte & (mask(31) << 21);
204 entry.uncacheable = uncacheable;
205 entry.global = pte.g;
206 entry.patBit = bits(pte, 12);
207 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
208 tlb->insert(entry.vaddr, entry);
209 nextState = Ready;
210 delete read->req;
211 delete read;
212 read = NULL;
213 return;
214 }
215 case PAEPTE:
216 doWrite = !pte.a;
217 pte.a = 1;
218 entry.writable = entry.writable && pte.w;
219 entry.user = entry.user && pte.u;
220 if (badNX)
221 panic("NX violation!\n");
222 if (!pte.p)
223 panic("Page at %#x not present!\n", entry.vaddr);
224 entry.paddr = (uint64_t)pte & (mask(40) << 12);
225 entry.uncacheable = uncacheable;
226 entry.global = pte.g;
227 entry.patBit = bits(pte, 7);
228 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
229 tlb->insert(entry.vaddr, entry);
230 nextState = Ready;
231 delete read->req;
232 delete read;
233 read = NULL;
234 return;
235 case PSEPD:
236 doWrite = !pte.a;
237 pte.a = 1;
238 entry.writable = pte.w;
239 entry.user = pte.u;
240 if (!pte.p)
241 panic("Page at %#x not present!\n", entry.vaddr);
242 if (!pte.ps) {
243 // 4 KB page
244 entry.size = 4 * (1 << 10);
245 nextRead =
246 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
247 nextState = PTE;
248 break;
249 } else {
250 // 4 MB page
251 entry.size = 4 * (1 << 20);
252 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
253 entry.uncacheable = uncacheable;
254 entry.global = pte.g;
255 entry.patBit = bits(pte, 12);
256 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
257 tlb->insert(entry.vaddr, entry);
258 nextState = Ready;
259 delete read->req;
260 delete read;
261 read = NULL;
262 return;
263 }
264 case PD:
265 doWrite = !pte.a;
266 pte.a = 1;
267 entry.writable = pte.w;
268 entry.user = pte.u;
269 if (!pte.p)
270 panic("Page at %#x not present!\n", entry.vaddr);
271 // 4 KB page
272 entry.size = 4 * (1 << 10);
273 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
274 nextState = PTE;
275 break;
276 nextState = PTE;
277 break;
278 case PTE:
279 doWrite = !pte.a;
280 pte.a = 1;
281 entry.writable = pte.w;
282 entry.user = pte.u;
283 if (!pte.p)
284 panic("Page at %#x not present!\n", entry.vaddr);
285 entry.paddr = (uint64_t)pte & (mask(20) << 12);
286 entry.uncacheable = uncacheable;
287 entry.global = pte.g;
288 entry.patBit = bits(pte, 7);
289 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
290 tlb->insert(entry.vaddr, entry);
291 nextState = Ready;
292 delete read->req;
293 delete read;
294 read = NULL;
295 return;
296 default:
297 panic("Unknown page table walker state %d!\n");
298 }
299 PacketPtr oldRead = read;
300 //If we didn't return, we're setting up another read.
301 Request::Flags flags = oldRead->req->getFlags();
302 flags.set(Request::UNCACHEABLE, uncacheable);
303 RequestPtr request =
304 new Request(nextRead, oldRead->getSize(), flags);
305 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
306 read->allocate();
307 //If we need to write, adjust the read packet to write the modified value
308 //back to memory.
309 if (doWrite) {
310 write = oldRead;
311 write->set<uint64_t>(pte);
312 write->cmd = MemCmd::WriteReq;
313 write->setDest(Packet::Broadcast);
314 } else {
315 write = NULL;
316 delete oldRead->req;
317 delete oldRead;
318 }
319}
320
321void
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
87void
88Walker::doNext(PacketPtr &read, 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 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)
110 panic("NX violation!\n");
111 entry.noExec = pte.nx;
112 if (!pte.p)
113 panic("Page at %#x not present!\n", entry.vaddr);
114 nextState = LongPDP;
115 break;
116 case LongPDP:
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)
123 panic("NX violation!\n");
124 if (!pte.p)
125 panic("Page at %#x not present!\n", entry.vaddr);
126 nextState = LongPD;
127 break;
128 case LongPD:
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)
134 panic("NX violation!\n");
135 if (!pte.p)
136 panic("Page at %#x not present!\n", entry.vaddr);
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 nextState = Ready;
154 delete read->req;
155 delete read;
156 read = NULL;
157 return;
158 }
159 case LongPTE:
160 doWrite = !pte.a;
161 pte.a = 1;
162 entry.writable = entry.writable && pte.w;
163 entry.user = entry.user && pte.u;
164 if (badNX)
165 panic("NX violation!\n");
166 if (!pte.p)
167 panic("Page at %#x not present!\n", entry.vaddr);
168 entry.paddr = (uint64_t)pte & (mask(40) << 12);
169 entry.uncacheable = uncacheable;
170 entry.global = pte.g;
171 entry.patBit = bits(pte, 12);
172 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
173 tlb->insert(entry.vaddr, entry);
174 nextState = Ready;
175 delete read->req;
176 delete read;
177 read = NULL;
178 return;
179 case PAEPDP:
180 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
181 if (!pte.p)
182 panic("Page at %#x not present!\n", entry.vaddr);
183 nextState = PAEPD;
184 break;
185 case PAEPD:
186 doWrite = !pte.a;
187 pte.a = 1;
188 entry.writable = pte.w;
189 entry.user = pte.u;
190 if (badNX)
191 panic("NX violation!\n");
192 if (!pte.p)
193 panic("Page at %#x not present!\n", entry.vaddr);
194 if (!pte.ps) {
195 // 4 KB page
196 entry.size = 4 * (1 << 10);
197 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
198 nextState = PAEPTE;
199 break;
200 } else {
201 // 2 MB page
202 entry.size = 2 * (1 << 20);
203 entry.paddr = (uint64_t)pte & (mask(31) << 21);
204 entry.uncacheable = uncacheable;
205 entry.global = pte.g;
206 entry.patBit = bits(pte, 12);
207 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
208 tlb->insert(entry.vaddr, entry);
209 nextState = Ready;
210 delete read->req;
211 delete read;
212 read = NULL;
213 return;
214 }
215 case PAEPTE:
216 doWrite = !pte.a;
217 pte.a = 1;
218 entry.writable = entry.writable && pte.w;
219 entry.user = entry.user && pte.u;
220 if (badNX)
221 panic("NX violation!\n");
222 if (!pte.p)
223 panic("Page at %#x not present!\n", entry.vaddr);
224 entry.paddr = (uint64_t)pte & (mask(40) << 12);
225 entry.uncacheable = uncacheable;
226 entry.global = pte.g;
227 entry.patBit = bits(pte, 7);
228 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
229 tlb->insert(entry.vaddr, entry);
230 nextState = Ready;
231 delete read->req;
232 delete read;
233 read = NULL;
234 return;
235 case PSEPD:
236 doWrite = !pte.a;
237 pte.a = 1;
238 entry.writable = pte.w;
239 entry.user = pte.u;
240 if (!pte.p)
241 panic("Page at %#x not present!\n", entry.vaddr);
242 if (!pte.ps) {
243 // 4 KB page
244 entry.size = 4 * (1 << 10);
245 nextRead =
246 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
247 nextState = PTE;
248 break;
249 } else {
250 // 4 MB page
251 entry.size = 4 * (1 << 20);
252 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
253 entry.uncacheable = uncacheable;
254 entry.global = pte.g;
255 entry.patBit = bits(pte, 12);
256 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
257 tlb->insert(entry.vaddr, entry);
258 nextState = Ready;
259 delete read->req;
260 delete read;
261 read = NULL;
262 return;
263 }
264 case PD:
265 doWrite = !pte.a;
266 pte.a = 1;
267 entry.writable = pte.w;
268 entry.user = pte.u;
269 if (!pte.p)
270 panic("Page at %#x not present!\n", entry.vaddr);
271 // 4 KB page
272 entry.size = 4 * (1 << 10);
273 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
274 nextState = PTE;
275 break;
276 nextState = PTE;
277 break;
278 case PTE:
279 doWrite = !pte.a;
280 pte.a = 1;
281 entry.writable = pte.w;
282 entry.user = pte.u;
283 if (!pte.p)
284 panic("Page at %#x not present!\n", entry.vaddr);
285 entry.paddr = (uint64_t)pte & (mask(20) << 12);
286 entry.uncacheable = uncacheable;
287 entry.global = pte.g;
288 entry.patBit = bits(pte, 7);
289 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
290 tlb->insert(entry.vaddr, entry);
291 nextState = Ready;
292 delete read->req;
293 delete read;
294 read = NULL;
295 return;
296 default:
297 panic("Unknown page table walker state %d!\n");
298 }
299 PacketPtr oldRead = read;
300 //If we didn't return, we're setting up another read.
301 Request::Flags flags = oldRead->req->getFlags();
302 flags.set(Request::UNCACHEABLE, uncacheable);
303 RequestPtr request =
304 new Request(nextRead, oldRead->getSize(), flags);
305 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
306 read->allocate();
307 //If we need to write, adjust the read packet to write the modified value
308 //back to memory.
309 if (doWrite) {
310 write = oldRead;
311 write->set<uint64_t>(pte);
312 write->cmd = MemCmd::WriteReq;
313 write->setDest(Packet::Broadcast);
314 } else {
315 write = NULL;
316 delete oldRead->req;
317 delete oldRead;
318 }
319}
320
321void
322Walker::start(ThreadContext * _tc, Addr vaddr)
322Walker::start(ThreadContext * _tc, Addr vaddr, bool _write, bool _execute)
323{
324 assert(state == Ready);
325 assert(!tc);
326 tc = _tc;
323{
324 assert(state == Ready);
325 assert(!tc);
326 tc = _tc;
327 execute = _execute;
328 write = _write;
327
328 VAddr addr = vaddr;
329
330 //Figure out what we're doing.
331 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
332 Addr top = 0;
333 // Check if we're in long mode or not
334 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
335 size = 8;
336 if (efer.lma) {
337 // Do long mode.
338 state = LongPML4;
339 top = (cr3.longPdtb << 12) + addr.longl4 * size;
340 } else {
341 // We're in some flavor of legacy mode.
342 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
343 if (cr4.pae) {
344 // Do legacy PAE.
345 state = PAEPDP;
346 top = (cr3.paePdtb << 5) + addr.pael3 * size;
347 } else {
348 size = 4;
349 top = (cr3.pdtb << 12) + addr.norml2 * size;
350 if (cr4.pse) {
351 // Do legacy PSE.
352 state = PSEPD;
353 } else {
354 // Do legacy non PSE.
355 state = PD;
356 }
357 }
358 }
359
360 nextState = Ready;
361 entry.vaddr = vaddr;
362
363 enableNX = efer.nxe;
364
365 Request::Flags flags = Request::PHYSICAL;
366 if (cr3.pcd)
367 flags.set(Request::UNCACHEABLE);
368 RequestPtr request = new Request(top, size, flags);
369 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
370 read->allocate();
371 Enums::MemoryMode memMode = sys->getMemoryMode();
372 if (memMode == Enums::timing) {
373 tc->suspend();
374 port.sendTiming(read);
375 } else if (memMode == Enums::atomic) {
376 do {
377 port.sendAtomic(read);
378 PacketPtr write = NULL;
379 doNext(read, write);
380 state = nextState;
381 nextState = Ready;
382 if (write)
383 port.sendAtomic(write);
384 } while(read);
385 tc = NULL;
386 state = Ready;
387 nextState = Waiting;
388 } else {
389 panic("Unrecognized memory system mode.\n");
390 }
391}
392
393bool
394Walker::WalkerPort::recvTiming(PacketPtr pkt)
395{
396 return walker->recvTiming(pkt);
397}
398
399bool
400Walker::recvTiming(PacketPtr pkt)
401{
402 inflight--;
403 if (pkt->isResponse() && !pkt->wasNacked()) {
404 if (pkt->isRead()) {
405 assert(inflight);
406 assert(state == Waiting);
407 assert(!read);
408 state = nextState;
409 nextState = Ready;
410 PacketPtr write = NULL;
411 doNext(pkt, write);
412 state = Waiting;
413 read = pkt;
414 if (write) {
415 writes.push_back(write);
416 }
417 sendPackets();
418 } else {
419 sendPackets();
420 }
421 if (inflight == 0 && read == NULL && writes.size() == 0) {
422 tc->activate(0);
423 tc = NULL;
424 state = Ready;
425 nextState = Waiting;
426 }
427 } else if (pkt->wasNacked()) {
428 pkt->reinitNacked();
429 if (!port.sendTiming(pkt)) {
430 retrying = true;
431 if (pkt->isWrite()) {
432 writes.push_back(pkt);
433 } else {
434 assert(!read);
435 read = pkt;
436 }
437 } else {
438 inflight++;
439 }
440 }
441 return true;
442}
443
444Tick
445Walker::WalkerPort::recvAtomic(PacketPtr pkt)
446{
447 return 0;
448}
449
450void
451Walker::WalkerPort::recvFunctional(PacketPtr pkt)
452{
453 return;
454}
455
456void
457Walker::WalkerPort::recvStatusChange(Status status)
458{
459 if (status == RangeChange) {
460 if (!snoopRangeSent) {
461 snoopRangeSent = true;
462 sendStatusChange(Port::RangeChange);
463 }
464 return;
465 }
466
467 panic("Unexpected recvStatusChange.\n");
468}
469
470void
471Walker::WalkerPort::recvRetry()
472{
473 walker->recvRetry();
474}
475
476void
477Walker::recvRetry()
478{
479 retrying = false;
480 sendPackets();
481}
482
483void
484Walker::sendPackets()
485{
486 //If we're already waiting for the port to become available, just return.
487 if (retrying)
488 return;
489
490 //Reads always have priority
491 if (read) {
492 if (!port.sendTiming(read)) {
493 retrying = true;
494 return;
495 } else {
496 inflight++;
497 delete read->req;
498 delete read;
499 read = NULL;
500 }
501 }
502 //Send off as many of the writes as we can.
503 while (writes.size()) {
504 PacketPtr write = writes.back();
505 if (!port.sendTiming(write)) {
506 retrying = true;
507 return;
508 } else {
509 inflight++;
510 delete write->req;
511 delete write;
512 writes.pop_back();
513 }
514 }
515}
516
517Port *
518Walker::getPort(const std::string &if_name, int idx)
519{
520 if (if_name == "port")
521 return &port;
522 else
523 panic("No page table walker port named %s!\n", if_name);
524}
525
526}
527
528X86ISA::Walker *
529X86PagetableWalkerParams::create()
530{
531 return new X86ISA::Walker(this);
532}
329
330 VAddr addr = vaddr;
331
332 //Figure out what we're doing.
333 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
334 Addr top = 0;
335 // Check if we're in long mode or not
336 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
337 size = 8;
338 if (efer.lma) {
339 // Do long mode.
340 state = LongPML4;
341 top = (cr3.longPdtb << 12) + addr.longl4 * size;
342 } else {
343 // We're in some flavor of legacy mode.
344 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
345 if (cr4.pae) {
346 // Do legacy PAE.
347 state = PAEPDP;
348 top = (cr3.paePdtb << 5) + addr.pael3 * size;
349 } else {
350 size = 4;
351 top = (cr3.pdtb << 12) + addr.norml2 * size;
352 if (cr4.pse) {
353 // Do legacy PSE.
354 state = PSEPD;
355 } else {
356 // Do legacy non PSE.
357 state = PD;
358 }
359 }
360 }
361
362 nextState = Ready;
363 entry.vaddr = vaddr;
364
365 enableNX = efer.nxe;
366
367 Request::Flags flags = Request::PHYSICAL;
368 if (cr3.pcd)
369 flags.set(Request::UNCACHEABLE);
370 RequestPtr request = new Request(top, size, flags);
371 read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
372 read->allocate();
373 Enums::MemoryMode memMode = sys->getMemoryMode();
374 if (memMode == Enums::timing) {
375 tc->suspend();
376 port.sendTiming(read);
377 } else if (memMode == Enums::atomic) {
378 do {
379 port.sendAtomic(read);
380 PacketPtr write = NULL;
381 doNext(read, write);
382 state = nextState;
383 nextState = Ready;
384 if (write)
385 port.sendAtomic(write);
386 } while(read);
387 tc = NULL;
388 state = Ready;
389 nextState = Waiting;
390 } else {
391 panic("Unrecognized memory system mode.\n");
392 }
393}
394
395bool
396Walker::WalkerPort::recvTiming(PacketPtr pkt)
397{
398 return walker->recvTiming(pkt);
399}
400
401bool
402Walker::recvTiming(PacketPtr pkt)
403{
404 inflight--;
405 if (pkt->isResponse() && !pkt->wasNacked()) {
406 if (pkt->isRead()) {
407 assert(inflight);
408 assert(state == Waiting);
409 assert(!read);
410 state = nextState;
411 nextState = Ready;
412 PacketPtr write = NULL;
413 doNext(pkt, write);
414 state = Waiting;
415 read = pkt;
416 if (write) {
417 writes.push_back(write);
418 }
419 sendPackets();
420 } else {
421 sendPackets();
422 }
423 if (inflight == 0 && read == NULL && writes.size() == 0) {
424 tc->activate(0);
425 tc = NULL;
426 state = Ready;
427 nextState = Waiting;
428 }
429 } else if (pkt->wasNacked()) {
430 pkt->reinitNacked();
431 if (!port.sendTiming(pkt)) {
432 retrying = true;
433 if (pkt->isWrite()) {
434 writes.push_back(pkt);
435 } else {
436 assert(!read);
437 read = pkt;
438 }
439 } else {
440 inflight++;
441 }
442 }
443 return true;
444}
445
446Tick
447Walker::WalkerPort::recvAtomic(PacketPtr pkt)
448{
449 return 0;
450}
451
452void
453Walker::WalkerPort::recvFunctional(PacketPtr pkt)
454{
455 return;
456}
457
458void
459Walker::WalkerPort::recvStatusChange(Status status)
460{
461 if (status == RangeChange) {
462 if (!snoopRangeSent) {
463 snoopRangeSent = true;
464 sendStatusChange(Port::RangeChange);
465 }
466 return;
467 }
468
469 panic("Unexpected recvStatusChange.\n");
470}
471
472void
473Walker::WalkerPort::recvRetry()
474{
475 walker->recvRetry();
476}
477
478void
479Walker::recvRetry()
480{
481 retrying = false;
482 sendPackets();
483}
484
485void
486Walker::sendPackets()
487{
488 //If we're already waiting for the port to become available, just return.
489 if (retrying)
490 return;
491
492 //Reads always have priority
493 if (read) {
494 if (!port.sendTiming(read)) {
495 retrying = true;
496 return;
497 } else {
498 inflight++;
499 delete read->req;
500 delete read;
501 read = NULL;
502 }
503 }
504 //Send off as many of the writes as we can.
505 while (writes.size()) {
506 PacketPtr write = writes.back();
507 if (!port.sendTiming(write)) {
508 retrying = true;
509 return;
510 } else {
511 inflight++;
512 delete write->req;
513 delete write;
514 writes.pop_back();
515 }
516 }
517}
518
519Port *
520Walker::getPort(const std::string &if_name, int idx)
521{
522 if (if_name == "port")
523 return &port;
524 else
525 panic("No page table walker port named %s!\n", if_name);
526}
527
528}
529
530X86ISA::Walker *
531X86PagetableWalkerParams::create()
532{
533 return new X86ISA::Walker(this);
534}