pagetable_walker.cc revision 6022:410194bb3049
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 && execute && enableNX; 102 switch(state) { 103 case LongPML4: 104 DPRINTF(PageTableWalker, 105 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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"); 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} 577