1/* 2 * Copyright (c) 2007 The Hewlett-Packard Development Company 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Gabe Black 38 */ 39 40#include "arch/x86/pagetable.hh" 41#include "arch/x86/pagetable_walker.hh" 42#include "arch/x86/tlb.hh" 43#include "arch/x86/vtophys.hh" 44#include "base/bitfield.hh" 45#include "cpu/base.hh" 46#include "cpu/thread_context.hh" 47#include "debug/PageTableWalker.hh" 48#include "mem/packet_access.hh" 49#include "mem/request.hh" 50#include "sim/system.hh" 51 52namespace X86ISA { 53 54// Unfortunately, the placement of the base field in a page table entry is 55// very erratic and would make a mess here. It might be moved here at some 56// point in the future. 57BitUnion64(PageTableEntry) 58 Bitfield<63> nx; 59 Bitfield<11, 9> avl; 60 Bitfield<8> g; 61 Bitfield<7> ps; 62 Bitfield<6> d; 63 Bitfield<5> a; 64 Bitfield<4> pcd; 65 Bitfield<3> pwt; 66 Bitfield<2> u; 67 Bitfield<1> w; 68 Bitfield<0> p; 69EndBitUnion(PageTableEntry) 70 71Fault 72Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, 73 RequestPtr _req, BaseTLB::Mode _mode) 74{ 75 // TODO: in timing mode, instead of blocking when there are other 76 // outstanding requests, see if this request can be coalesced with 77 // another one (i.e. either coalesce or start walk) 78 WalkerState * newState = new WalkerState(this, _translation, _req); 79 newState->initState(_tc, _mode, sys->getMemoryMode() == Enums::timing); 80 if (currStates.size()) { 81 assert(newState->isTiming()); 82 DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size()); 83 currStates.push_back(newState); 84 return NoFault; 85 } else { 86 currStates.push_back(newState); 87 Fault fault = newState->startWalk(); 88 if (!newState->isTiming()) { 89 currStates.pop_front(); 90 delete newState; 91 } 92 return fault; 93 } 94} 95 96Fault 97Walker::startFunctional(ThreadContext * _tc, Addr &addr, Addr &pageSize, 98 BaseTLB::Mode _mode) 99{ 100 funcState.initState(_tc, _mode); 101 return funcState.startFunctional(addr, pageSize); 102} 103 104bool 105Walker::WalkerPort::recvTiming(PacketPtr pkt) 106{ 107 return walker->recvTiming(pkt); 108} 109 110bool 111Walker::recvTiming(PacketPtr pkt) 112{ 113 if (pkt->isResponse() || pkt->wasNacked()) { 114 WalkerSenderState * senderState = 115 dynamic_cast<WalkerSenderState *>(pkt->senderState); 116 pkt->senderState = senderState->saved; 117 WalkerState * senderWalk = senderState->senderWalk; 118 bool walkComplete = senderWalk->recvPacket(pkt); 119 delete senderState; 120 if (walkComplete) { 121 std::list<WalkerState *>::iterator iter; 122 for (iter = currStates.begin(); iter != currStates.end(); iter++) { 123 WalkerState * walkerState = *(iter); 124 if (walkerState == senderWalk) { 125 iter = currStates.erase(iter); 126 break; 127 } 128 } 129 delete senderWalk; 130 // Since we block requests when another is outstanding, we 131 // need to check if there is a waiting request to be serviced 132 if (currStates.size()) { 133 WalkerState * newState = currStates.front(); 134 if (!newState->wasStarted()) 135 newState->startWalk(); 136 } 137 } 138 } else { 139 DPRINTF(PageTableWalker, "Received strange packet\n"); 140 } 141 return true; 142} 143 144Tick 145Walker::WalkerPort::recvAtomic(PacketPtr pkt) 146{ 147 return 0; 148} 149 150void 151Walker::WalkerPort::recvFunctional(PacketPtr pkt) 152{ 153 return; 154} 155 156void 157Walker::WalkerPort::recvRangeChange() 158{ 159} 160 161void 162Walker::WalkerPort::recvRetry() 163{ 164 walker->recvRetry(); 165} 166 167void 168Walker::recvRetry() 169{ 170 std::list<WalkerState *>::iterator iter; 171 for (iter = currStates.begin(); iter != currStates.end(); iter++) { 172 WalkerState * walkerState = *(iter); 173 if (walkerState->isRetrying()) { 174 walkerState->retry(); 175 } 176 } 177} 178 179bool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt) 180{ 181 pkt->senderState = new WalkerSenderState(sendingState, pkt->senderState); 182 return port.sendTiming(pkt); 183} 184 185Port * 186Walker::getPort(const std::string &if_name, int idx) 187{ 188 if (if_name == "port") 189 return &port; 190 else 191 panic("No page table walker port named %s!\n", if_name); 192} 193 194void 195Walker::WalkerState::initState(ThreadContext * _tc, 196 BaseTLB::Mode _mode, bool _isTiming) 197{ 198 assert(state == Ready); 199 started = false; 200 tc = _tc; 201 mode = _mode; 202 timing = _isTiming; 203} 204 205Fault 206Walker::WalkerState::startWalk() 207{ 208 Fault fault = NoFault; 209 assert(started == false); 210 started = true; 211 setupWalk(req->getVaddr()); 212 if (timing) { 213 nextState = state; 214 state = Waiting; 215 timingFault = NoFault; 216 sendPackets(); 217 } else { 218 do { 219 walker->port.sendAtomic(read); 220 PacketPtr write = NULL; 221 fault = stepWalk(write); 222 assert(fault == NoFault || read == NULL); 223 state = nextState; 224 nextState = Ready; 225 if (write) 226 walker->port.sendAtomic(write); 227 } while(read); 228 state = Ready; 229 nextState = Waiting; 230 } 231 return fault; 232} 233 234Fault 235Walker::WalkerState::startFunctional(Addr &addr, Addr &pageSize) 236{ 237 Fault fault = NoFault; 238 assert(started == false); 239 started = true; 240 setupWalk(addr); 241 242 do { 243 walker->port.sendFunctional(read); 244 // On a functional access (page table lookup), writes should 245 // not happen so this pointer is ignored after stepWalk 246 PacketPtr write = NULL; 247 fault = stepWalk(write); 248 assert(fault == NoFault || read == NULL); 249 state = nextState; 250 nextState = Ready; 251 } while(read); 252 pageSize = entry.size; 253 addr = entry.paddr; 254 255 return fault; 256} 257 258Fault 259Walker::WalkerState::stepWalk(PacketPtr &write) 260{ 261 assert(state != Ready && state != Waiting); 262 Fault fault = NoFault; 263 write = NULL; 264 PageTableEntry pte; 265 if (dataSize == 8) 266 pte = read->get<uint64_t>(); 267 else 268 pte = read->get<uint32_t>(); 269 VAddr vaddr = entry.vaddr; 270 bool uncacheable = pte.pcd; 271 Addr nextRead = 0; 272 bool doWrite = false; 273 bool doTLBInsert = false; 274 bool doEndWalk = false; 275 bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX; 276 switch(state) { 277 case LongPML4: 278 DPRINTF(PageTableWalker, 279 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 280 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize; 281 doWrite = !pte.a; 282 pte.a = 1; 283 entry.writable = pte.w; 284 entry.user = pte.u; 285 if (badNX || !pte.p) { 286 doEndWalk = true; 287 fault = pageFault(pte.p); 288 break; 289 } 290 entry.noExec = pte.nx; 291 nextState = LongPDP; 292 break; 293 case LongPDP: 294 DPRINTF(PageTableWalker, 295 "Got long mode PDP entry %#016x.\n", (uint64_t)pte); 296 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize; 297 doWrite = !pte.a; 298 pte.a = 1; 299 entry.writable = entry.writable && pte.w; 300 entry.user = entry.user && pte.u; 301 if (badNX || !pte.p) { 302 doEndWalk = true; 303 fault = pageFault(pte.p); 304 break; 305 } 306 nextState = LongPD; 307 break; 308 case LongPD: 309 DPRINTF(PageTableWalker, 310 "Got long mode PD entry %#016x.\n", (uint64_t)pte); 311 doWrite = !pte.a; 312 pte.a = 1; 313 entry.writable = entry.writable && pte.w; 314 entry.user = entry.user && pte.u; 315 if (badNX || !pte.p) { 316 doEndWalk = true; 317 fault = pageFault(pte.p); 318 break; 319 } 320 if (!pte.ps) { 321 // 4 KB page 322 entry.size = 4 * (1 << 10); 323 nextRead = 324 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize; 325 nextState = LongPTE; 326 break; 327 } else { 328 // 2 MB page 329 entry.size = 2 * (1 << 20); 330 entry.paddr = (uint64_t)pte & (mask(31) << 21); 331 entry.uncacheable = uncacheable; 332 entry.global = pte.g; 333 entry.patBit = bits(pte, 12); 334 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 335 doTLBInsert = true; 336 doEndWalk = true; 337 break; 338 } 339 case LongPTE: 340 DPRINTF(PageTableWalker, 341 "Got long mode PTE entry %#016x.\n", (uint64_t)pte); 342 doWrite = !pte.a; 343 pte.a = 1; 344 entry.writable = entry.writable && pte.w; 345 entry.user = entry.user && pte.u; 346 if (badNX || !pte.p) { 347 doEndWalk = true; 348 fault = pageFault(pte.p); 349 break; 350 } 351 entry.paddr = (uint64_t)pte & (mask(40) << 12); 352 entry.uncacheable = uncacheable; 353 entry.global = pte.g; 354 entry.patBit = bits(pte, 12); 355 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 356 doTLBInsert = true; 357 doEndWalk = true; 358 break; 359 case PAEPDP: 360 DPRINTF(PageTableWalker, 361 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); 362 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize; 363 if (!pte.p) { 364 doEndWalk = true; 365 fault = pageFault(pte.p); 366 break; 367 } 368 nextState = PAEPD; 369 break; 370 case PAEPD: 371 DPRINTF(PageTableWalker, 372 "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); 373 doWrite = !pte.a; 374 pte.a = 1; 375 entry.writable = pte.w; 376 entry.user = pte.u; 377 if (badNX || !pte.p) { 378 doEndWalk = true; 379 fault = pageFault(pte.p); 380 break; 381 } 382 if (!pte.ps) { 383 // 4 KB page 384 entry.size = 4 * (1 << 10); 385 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize; 386 nextState = PAEPTE; 387 break; 388 } else { 389 // 2 MB page 390 entry.size = 2 * (1 << 20); 391 entry.paddr = (uint64_t)pte & (mask(31) << 21); 392 entry.uncacheable = uncacheable; 393 entry.global = pte.g; 394 entry.patBit = bits(pte, 12); 395 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 396 doTLBInsert = true; 397 doEndWalk = true; 398 break; 399 } 400 case PAEPTE: 401 DPRINTF(PageTableWalker, 402 "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); 403 doWrite = !pte.a; 404 pte.a = 1; 405 entry.writable = entry.writable && pte.w; 406 entry.user = entry.user && pte.u; 407 if (badNX || !pte.p) { 408 doEndWalk = true; 409 fault = pageFault(pte.p); 410 break; 411 } 412 entry.paddr = (uint64_t)pte & (mask(40) << 12); 413 entry.uncacheable = uncacheable; 414 entry.global = pte.g; 415 entry.patBit = bits(pte, 7); 416 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 417 doTLBInsert = true; 418 doEndWalk = true; 419 break; 420 case PSEPD: 421 DPRINTF(PageTableWalker, 422 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); 423 doWrite = !pte.a; 424 pte.a = 1; 425 entry.writable = pte.w; 426 entry.user = pte.u; 427 if (!pte.p) { 428 doEndWalk = true; 429 fault = pageFault(pte.p); 430 break; 431 } 432 if (!pte.ps) { 433 // 4 KB page 434 entry.size = 4 * (1 << 10); 435 nextRead = 436 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 437 nextState = PTE; 438 break; 439 } else { 440 // 4 MB page 441 entry.size = 4 * (1 << 20); 442 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; 443 entry.uncacheable = uncacheable; 444 entry.global = pte.g; 445 entry.patBit = bits(pte, 12); 446 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); 447 doTLBInsert = true; 448 doEndWalk = true; 449 break; 450 } 451 case PD: 452 DPRINTF(PageTableWalker, 453 "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); 454 doWrite = !pte.a; 455 pte.a = 1; 456 entry.writable = pte.w; 457 entry.user = pte.u; 458 if (!pte.p) { 459 doEndWalk = true; 460 fault = pageFault(pte.p); 461 break; 462 } 463 // 4 KB page 464 entry.size = 4 * (1 << 10); 465 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 466 nextState = PTE; 467 break; 468 case PTE: 469 DPRINTF(PageTableWalker, 470 "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); 471 doWrite = !pte.a; 472 pte.a = 1; 473 entry.writable = pte.w; 474 entry.user = pte.u; 475 if (!pte.p) { 476 doEndWalk = true; 477 fault = pageFault(pte.p); 478 break; 479 } 480 entry.paddr = (uint64_t)pte & (mask(20) << 12); 481 entry.uncacheable = uncacheable; 482 entry.global = pte.g; 483 entry.patBit = bits(pte, 7); 484 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 485 doTLBInsert = true; 486 doEndWalk = true; 487 break; 488 default: 489 panic("Unknown page table walker state %d!\n"); 490 } 491 if (doEndWalk) { 492 if (doTLBInsert) 493 if (!functional) 494 walker->tlb->insert(entry.vaddr, entry); 495 endWalk(); 496 } else { 497 PacketPtr oldRead = read; 498 //If we didn't return, we're setting up another read. 499 Request::Flags flags = oldRead->req->getFlags(); 500 flags.set(Request::UNCACHEABLE, uncacheable); 501 RequestPtr request =
| 1/* 2 * Copyright (c) 2007 The Hewlett-Packard Development Company 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Gabe Black 38 */ 39 40#include "arch/x86/pagetable.hh" 41#include "arch/x86/pagetable_walker.hh" 42#include "arch/x86/tlb.hh" 43#include "arch/x86/vtophys.hh" 44#include "base/bitfield.hh" 45#include "cpu/base.hh" 46#include "cpu/thread_context.hh" 47#include "debug/PageTableWalker.hh" 48#include "mem/packet_access.hh" 49#include "mem/request.hh" 50#include "sim/system.hh" 51 52namespace X86ISA { 53 54// Unfortunately, the placement of the base field in a page table entry is 55// very erratic and would make a mess here. It might be moved here at some 56// point in the future. 57BitUnion64(PageTableEntry) 58 Bitfield<63> nx; 59 Bitfield<11, 9> avl; 60 Bitfield<8> g; 61 Bitfield<7> ps; 62 Bitfield<6> d; 63 Bitfield<5> a; 64 Bitfield<4> pcd; 65 Bitfield<3> pwt; 66 Bitfield<2> u; 67 Bitfield<1> w; 68 Bitfield<0> p; 69EndBitUnion(PageTableEntry) 70 71Fault 72Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, 73 RequestPtr _req, BaseTLB::Mode _mode) 74{ 75 // TODO: in timing mode, instead of blocking when there are other 76 // outstanding requests, see if this request can be coalesced with 77 // another one (i.e. either coalesce or start walk) 78 WalkerState * newState = new WalkerState(this, _translation, _req); 79 newState->initState(_tc, _mode, sys->getMemoryMode() == Enums::timing); 80 if (currStates.size()) { 81 assert(newState->isTiming()); 82 DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size()); 83 currStates.push_back(newState); 84 return NoFault; 85 } else { 86 currStates.push_back(newState); 87 Fault fault = newState->startWalk(); 88 if (!newState->isTiming()) { 89 currStates.pop_front(); 90 delete newState; 91 } 92 return fault; 93 } 94} 95 96Fault 97Walker::startFunctional(ThreadContext * _tc, Addr &addr, Addr &pageSize, 98 BaseTLB::Mode _mode) 99{ 100 funcState.initState(_tc, _mode); 101 return funcState.startFunctional(addr, pageSize); 102} 103 104bool 105Walker::WalkerPort::recvTiming(PacketPtr pkt) 106{ 107 return walker->recvTiming(pkt); 108} 109 110bool 111Walker::recvTiming(PacketPtr pkt) 112{ 113 if (pkt->isResponse() || pkt->wasNacked()) { 114 WalkerSenderState * senderState = 115 dynamic_cast<WalkerSenderState *>(pkt->senderState); 116 pkt->senderState = senderState->saved; 117 WalkerState * senderWalk = senderState->senderWalk; 118 bool walkComplete = senderWalk->recvPacket(pkt); 119 delete senderState; 120 if (walkComplete) { 121 std::list<WalkerState *>::iterator iter; 122 for (iter = currStates.begin(); iter != currStates.end(); iter++) { 123 WalkerState * walkerState = *(iter); 124 if (walkerState == senderWalk) { 125 iter = currStates.erase(iter); 126 break; 127 } 128 } 129 delete senderWalk; 130 // Since we block requests when another is outstanding, we 131 // need to check if there is a waiting request to be serviced 132 if (currStates.size()) { 133 WalkerState * newState = currStates.front(); 134 if (!newState->wasStarted()) 135 newState->startWalk(); 136 } 137 } 138 } else { 139 DPRINTF(PageTableWalker, "Received strange packet\n"); 140 } 141 return true; 142} 143 144Tick 145Walker::WalkerPort::recvAtomic(PacketPtr pkt) 146{ 147 return 0; 148} 149 150void 151Walker::WalkerPort::recvFunctional(PacketPtr pkt) 152{ 153 return; 154} 155 156void 157Walker::WalkerPort::recvRangeChange() 158{ 159} 160 161void 162Walker::WalkerPort::recvRetry() 163{ 164 walker->recvRetry(); 165} 166 167void 168Walker::recvRetry() 169{ 170 std::list<WalkerState *>::iterator iter; 171 for (iter = currStates.begin(); iter != currStates.end(); iter++) { 172 WalkerState * walkerState = *(iter); 173 if (walkerState->isRetrying()) { 174 walkerState->retry(); 175 } 176 } 177} 178 179bool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt) 180{ 181 pkt->senderState = new WalkerSenderState(sendingState, pkt->senderState); 182 return port.sendTiming(pkt); 183} 184 185Port * 186Walker::getPort(const std::string &if_name, int idx) 187{ 188 if (if_name == "port") 189 return &port; 190 else 191 panic("No page table walker port named %s!\n", if_name); 192} 193 194void 195Walker::WalkerState::initState(ThreadContext * _tc, 196 BaseTLB::Mode _mode, bool _isTiming) 197{ 198 assert(state == Ready); 199 started = false; 200 tc = _tc; 201 mode = _mode; 202 timing = _isTiming; 203} 204 205Fault 206Walker::WalkerState::startWalk() 207{ 208 Fault fault = NoFault; 209 assert(started == false); 210 started = true; 211 setupWalk(req->getVaddr()); 212 if (timing) { 213 nextState = state; 214 state = Waiting; 215 timingFault = NoFault; 216 sendPackets(); 217 } else { 218 do { 219 walker->port.sendAtomic(read); 220 PacketPtr write = NULL; 221 fault = stepWalk(write); 222 assert(fault == NoFault || read == NULL); 223 state = nextState; 224 nextState = Ready; 225 if (write) 226 walker->port.sendAtomic(write); 227 } while(read); 228 state = Ready; 229 nextState = Waiting; 230 } 231 return fault; 232} 233 234Fault 235Walker::WalkerState::startFunctional(Addr &addr, Addr &pageSize) 236{ 237 Fault fault = NoFault; 238 assert(started == false); 239 started = true; 240 setupWalk(addr); 241 242 do { 243 walker->port.sendFunctional(read); 244 // On a functional access (page table lookup), writes should 245 // not happen so this pointer is ignored after stepWalk 246 PacketPtr write = NULL; 247 fault = stepWalk(write); 248 assert(fault == NoFault || read == NULL); 249 state = nextState; 250 nextState = Ready; 251 } while(read); 252 pageSize = entry.size; 253 addr = entry.paddr; 254 255 return fault; 256} 257 258Fault 259Walker::WalkerState::stepWalk(PacketPtr &write) 260{ 261 assert(state != Ready && state != Waiting); 262 Fault fault = NoFault; 263 write = NULL; 264 PageTableEntry pte; 265 if (dataSize == 8) 266 pte = read->get<uint64_t>(); 267 else 268 pte = read->get<uint32_t>(); 269 VAddr vaddr = entry.vaddr; 270 bool uncacheable = pte.pcd; 271 Addr nextRead = 0; 272 bool doWrite = false; 273 bool doTLBInsert = false; 274 bool doEndWalk = false; 275 bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX; 276 switch(state) { 277 case LongPML4: 278 DPRINTF(PageTableWalker, 279 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 280 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize; 281 doWrite = !pte.a; 282 pte.a = 1; 283 entry.writable = pte.w; 284 entry.user = pte.u; 285 if (badNX || !pte.p) { 286 doEndWalk = true; 287 fault = pageFault(pte.p); 288 break; 289 } 290 entry.noExec = pte.nx; 291 nextState = LongPDP; 292 break; 293 case LongPDP: 294 DPRINTF(PageTableWalker, 295 "Got long mode PDP entry %#016x.\n", (uint64_t)pte); 296 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize; 297 doWrite = !pte.a; 298 pte.a = 1; 299 entry.writable = entry.writable && pte.w; 300 entry.user = entry.user && pte.u; 301 if (badNX || !pte.p) { 302 doEndWalk = true; 303 fault = pageFault(pte.p); 304 break; 305 } 306 nextState = LongPD; 307 break; 308 case LongPD: 309 DPRINTF(PageTableWalker, 310 "Got long mode PD entry %#016x.\n", (uint64_t)pte); 311 doWrite = !pte.a; 312 pte.a = 1; 313 entry.writable = entry.writable && pte.w; 314 entry.user = entry.user && pte.u; 315 if (badNX || !pte.p) { 316 doEndWalk = true; 317 fault = pageFault(pte.p); 318 break; 319 } 320 if (!pte.ps) { 321 // 4 KB page 322 entry.size = 4 * (1 << 10); 323 nextRead = 324 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize; 325 nextState = LongPTE; 326 break; 327 } else { 328 // 2 MB page 329 entry.size = 2 * (1 << 20); 330 entry.paddr = (uint64_t)pte & (mask(31) << 21); 331 entry.uncacheable = uncacheable; 332 entry.global = pte.g; 333 entry.patBit = bits(pte, 12); 334 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 335 doTLBInsert = true; 336 doEndWalk = true; 337 break; 338 } 339 case LongPTE: 340 DPRINTF(PageTableWalker, 341 "Got long mode PTE entry %#016x.\n", (uint64_t)pte); 342 doWrite = !pte.a; 343 pte.a = 1; 344 entry.writable = entry.writable && pte.w; 345 entry.user = entry.user && pte.u; 346 if (badNX || !pte.p) { 347 doEndWalk = true; 348 fault = pageFault(pte.p); 349 break; 350 } 351 entry.paddr = (uint64_t)pte & (mask(40) << 12); 352 entry.uncacheable = uncacheable; 353 entry.global = pte.g; 354 entry.patBit = bits(pte, 12); 355 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 356 doTLBInsert = true; 357 doEndWalk = true; 358 break; 359 case PAEPDP: 360 DPRINTF(PageTableWalker, 361 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); 362 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize; 363 if (!pte.p) { 364 doEndWalk = true; 365 fault = pageFault(pte.p); 366 break; 367 } 368 nextState = PAEPD; 369 break; 370 case PAEPD: 371 DPRINTF(PageTableWalker, 372 "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); 373 doWrite = !pte.a; 374 pte.a = 1; 375 entry.writable = pte.w; 376 entry.user = pte.u; 377 if (badNX || !pte.p) { 378 doEndWalk = true; 379 fault = pageFault(pte.p); 380 break; 381 } 382 if (!pte.ps) { 383 // 4 KB page 384 entry.size = 4 * (1 << 10); 385 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize; 386 nextState = PAEPTE; 387 break; 388 } else { 389 // 2 MB page 390 entry.size = 2 * (1 << 20); 391 entry.paddr = (uint64_t)pte & (mask(31) << 21); 392 entry.uncacheable = uncacheable; 393 entry.global = pte.g; 394 entry.patBit = bits(pte, 12); 395 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 396 doTLBInsert = true; 397 doEndWalk = true; 398 break; 399 } 400 case PAEPTE: 401 DPRINTF(PageTableWalker, 402 "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); 403 doWrite = !pte.a; 404 pte.a = 1; 405 entry.writable = entry.writable && pte.w; 406 entry.user = entry.user && pte.u; 407 if (badNX || !pte.p) { 408 doEndWalk = true; 409 fault = pageFault(pte.p); 410 break; 411 } 412 entry.paddr = (uint64_t)pte & (mask(40) << 12); 413 entry.uncacheable = uncacheable; 414 entry.global = pte.g; 415 entry.patBit = bits(pte, 7); 416 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 417 doTLBInsert = true; 418 doEndWalk = true; 419 break; 420 case PSEPD: 421 DPRINTF(PageTableWalker, 422 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); 423 doWrite = !pte.a; 424 pte.a = 1; 425 entry.writable = pte.w; 426 entry.user = pte.u; 427 if (!pte.p) { 428 doEndWalk = true; 429 fault = pageFault(pte.p); 430 break; 431 } 432 if (!pte.ps) { 433 // 4 KB page 434 entry.size = 4 * (1 << 10); 435 nextRead = 436 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 437 nextState = PTE; 438 break; 439 } else { 440 // 4 MB page 441 entry.size = 4 * (1 << 20); 442 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; 443 entry.uncacheable = uncacheable; 444 entry.global = pte.g; 445 entry.patBit = bits(pte, 12); 446 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); 447 doTLBInsert = true; 448 doEndWalk = true; 449 break; 450 } 451 case PD: 452 DPRINTF(PageTableWalker, 453 "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); 454 doWrite = !pte.a; 455 pte.a = 1; 456 entry.writable = pte.w; 457 entry.user = pte.u; 458 if (!pte.p) { 459 doEndWalk = true; 460 fault = pageFault(pte.p); 461 break; 462 } 463 // 4 KB page 464 entry.size = 4 * (1 << 10); 465 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 466 nextState = PTE; 467 break; 468 case PTE: 469 DPRINTF(PageTableWalker, 470 "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); 471 doWrite = !pte.a; 472 pte.a = 1; 473 entry.writable = pte.w; 474 entry.user = pte.u; 475 if (!pte.p) { 476 doEndWalk = true; 477 fault = pageFault(pte.p); 478 break; 479 } 480 entry.paddr = (uint64_t)pte & (mask(20) << 12); 481 entry.uncacheable = uncacheable; 482 entry.global = pte.g; 483 entry.patBit = bits(pte, 7); 484 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 485 doTLBInsert = true; 486 doEndWalk = true; 487 break; 488 default: 489 panic("Unknown page table walker state %d!\n"); 490 } 491 if (doEndWalk) { 492 if (doTLBInsert) 493 if (!functional) 494 walker->tlb->insert(entry.vaddr, entry); 495 endWalk(); 496 } else { 497 PacketPtr oldRead = read; 498 //If we didn't return, we're setting up another read. 499 Request::Flags flags = oldRead->req->getFlags(); 500 flags.set(Request::UNCACHEABLE, uncacheable); 501 RequestPtr request =
|
573 read = new Packet(request, MemCmd::ReadReq, Packet::Broadcast); 574 read->allocate(); 575} 576 577bool 578Walker::WalkerState::recvPacket(PacketPtr pkt) 579{ 580 if (pkt->isResponse() && !pkt->wasNacked()) { 581 assert(inflight); 582 assert(state == Waiting); 583 assert(!read); 584 inflight--; 585 if (pkt->isRead()) { 586 state = nextState; 587 nextState = Ready; 588 PacketPtr write = NULL; 589 read = pkt; 590 timingFault = stepWalk(write); 591 state = Waiting; 592 assert(timingFault == NoFault || read == NULL); 593 if (write) { 594 writes.push_back(write); 595 } 596 sendPackets(); 597 } else { 598 sendPackets(); 599 } 600 if (inflight == 0 && read == NULL && writes.size() == 0) { 601 state = Ready; 602 nextState = Waiting; 603 if (timingFault == NoFault) { 604 /* 605 * Finish the translation. Now that we now the right entry is 606 * in the TLB, this should work with no memory accesses. 607 * There could be new faults unrelated to the table walk like 608 * permissions violations, so we'll need the return value as 609 * well. 610 */ 611 bool delayedResponse; 612 Fault fault = walker->tlb->translate(req, tc, NULL, mode, 613 delayedResponse, true); 614 assert(!delayedResponse); 615 // Let the CPU continue. 616 translation->finish(fault, req, tc, mode); 617 } else { 618 // There was a fault during the walk. Let the CPU know. 619 translation->finish(timingFault, req, tc, mode); 620 } 621 return true; 622 } 623 } else if (pkt->wasNacked()) { 624 DPRINTF(PageTableWalker, "Request was nacked. Entering retry state\n"); 625 pkt->reinitNacked(); 626 if (!walker->sendTiming(this, pkt)) { 627 inflight--; 628 retrying = true; 629 if (pkt->isWrite()) { 630 writes.push_back(pkt); 631 } else { 632 assert(!read); 633 read = pkt; 634 } 635 } 636 } 637 return false; 638} 639 640void 641Walker::WalkerState::sendPackets() 642{ 643 //If we're already waiting for the port to become available, just return. 644 if (retrying) 645 return; 646 647 //Reads always have priority 648 if (read) { 649 PacketPtr pkt = read; 650 read = NULL; 651 inflight++; 652 if (!walker->sendTiming(this, pkt)) { 653 retrying = true; 654 read = pkt; 655 inflight--; 656 return; 657 } 658 } 659 //Send off as many of the writes as we can. 660 while (writes.size()) { 661 PacketPtr write = writes.back(); 662 writes.pop_back(); 663 inflight++; 664 if (!walker->sendTiming(this, write)) { 665 retrying = true; 666 writes.push_back(write); 667 inflight--; 668 return; 669 } 670 } 671} 672 673bool 674Walker::WalkerState::isRetrying() 675{ 676 return retrying; 677} 678 679bool 680Walker::WalkerState::isTiming() 681{ 682 return timing; 683} 684 685bool 686Walker::WalkerState::wasStarted() 687{ 688 return started; 689} 690 691void 692Walker::WalkerState::retry() 693{ 694 retrying = false; 695 sendPackets(); 696} 697 698Fault 699Walker::WalkerState::pageFault(bool present) 700{ 701 DPRINTF(PageTableWalker, "Raising page fault.\n"); 702 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 703 if (mode == BaseTLB::Execute && !enableNX) 704 mode = BaseTLB::Read; 705 return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false); 706} 707 708/* end namespace X86ISA */ } 709 710X86ISA::Walker * 711X86PagetableWalkerParams::create() 712{ 713 return new X86ISA::Walker(this); 714}
| 573 read = new Packet(request, MemCmd::ReadReq, Packet::Broadcast); 574 read->allocate(); 575} 576 577bool 578Walker::WalkerState::recvPacket(PacketPtr pkt) 579{ 580 if (pkt->isResponse() && !pkt->wasNacked()) { 581 assert(inflight); 582 assert(state == Waiting); 583 assert(!read); 584 inflight--; 585 if (pkt->isRead()) { 586 state = nextState; 587 nextState = Ready; 588 PacketPtr write = NULL; 589 read = pkt; 590 timingFault = stepWalk(write); 591 state = Waiting; 592 assert(timingFault == NoFault || read == NULL); 593 if (write) { 594 writes.push_back(write); 595 } 596 sendPackets(); 597 } else { 598 sendPackets(); 599 } 600 if (inflight == 0 && read == NULL && writes.size() == 0) { 601 state = Ready; 602 nextState = Waiting; 603 if (timingFault == NoFault) { 604 /* 605 * Finish the translation. Now that we now the right entry is 606 * in the TLB, this should work with no memory accesses. 607 * There could be new faults unrelated to the table walk like 608 * permissions violations, so we'll need the return value as 609 * well. 610 */ 611 bool delayedResponse; 612 Fault fault = walker->tlb->translate(req, tc, NULL, mode, 613 delayedResponse, true); 614 assert(!delayedResponse); 615 // Let the CPU continue. 616 translation->finish(fault, req, tc, mode); 617 } else { 618 // There was a fault during the walk. Let the CPU know. 619 translation->finish(timingFault, req, tc, mode); 620 } 621 return true; 622 } 623 } else if (pkt->wasNacked()) { 624 DPRINTF(PageTableWalker, "Request was nacked. Entering retry state\n"); 625 pkt->reinitNacked(); 626 if (!walker->sendTiming(this, pkt)) { 627 inflight--; 628 retrying = true; 629 if (pkt->isWrite()) { 630 writes.push_back(pkt); 631 } else { 632 assert(!read); 633 read = pkt; 634 } 635 } 636 } 637 return false; 638} 639 640void 641Walker::WalkerState::sendPackets() 642{ 643 //If we're already waiting for the port to become available, just return. 644 if (retrying) 645 return; 646 647 //Reads always have priority 648 if (read) { 649 PacketPtr pkt = read; 650 read = NULL; 651 inflight++; 652 if (!walker->sendTiming(this, pkt)) { 653 retrying = true; 654 read = pkt; 655 inflight--; 656 return; 657 } 658 } 659 //Send off as many of the writes as we can. 660 while (writes.size()) { 661 PacketPtr write = writes.back(); 662 writes.pop_back(); 663 inflight++; 664 if (!walker->sendTiming(this, write)) { 665 retrying = true; 666 writes.push_back(write); 667 inflight--; 668 return; 669 } 670 } 671} 672 673bool 674Walker::WalkerState::isRetrying() 675{ 676 return retrying; 677} 678 679bool 680Walker::WalkerState::isTiming() 681{ 682 return timing; 683} 684 685bool 686Walker::WalkerState::wasStarted() 687{ 688 return started; 689} 690 691void 692Walker::WalkerState::retry() 693{ 694 retrying = false; 695 sendPackets(); 696} 697 698Fault 699Walker::WalkerState::pageFault(bool present) 700{ 701 DPRINTF(PageTableWalker, "Raising page fault.\n"); 702 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 703 if (mode == BaseTLB::Execute && !enableNX) 704 mode = BaseTLB::Read; 705 return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false); 706} 707 708/* end namespace X86ISA */ } 709 710X86ISA::Walker * 711X86PagetableWalkerParams::create() 712{ 713 return new X86ISA::Walker(this); 714}
|