From 521d68c82a2399bfe32f282aa58708103369b99c Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Fri, 1 Oct 2010 16:03:27 -0500 Subject: ARM: Implement functional virtual to physical address translation for debugging and program introspection. --- src/arch/arm/SConscript | 2 +- src/arch/arm/table_walker.cc | 2 -- src/arch/arm/table_walker.hh | 25 +++++++++---- src/arch/arm/tlb.cc | 15 ++++++-- src/arch/arm/tlb.hh | 18 +++++++++- src/arch/arm/vtophys.cc | 86 ++++++++++++++++++++++++++++++++++++++++++-- src/arch/arm/vtophys.hh | 1 + 7 files changed, 134 insertions(+), 15 deletions(-) diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index 1c1f878a0..df84763b5 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -59,7 +59,6 @@ if env['TARGET_ISA'] == 'arm': Source('predecoder.cc') Source('nativetrace.cc') Source('tlb.cc') - Source('vtophys.cc') Source('utility.cc') SimObject('ArmNativeTrace.py') @@ -73,6 +72,7 @@ if env['TARGET_ISA'] == 'arm': Source('interrupts.cc') Source('stacktrace.cc') Source('system.cc') + Source('vtophys.cc') Source('linux/system.cc') Source('table_walker.cc') diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index ccd3a42bf..73dd24e1c 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -110,12 +110,10 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _ currState->vaddr = currState->req->getVaddr() & ~PcModeMask; currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR); sctlr = currState->sctlr; - currState->cpsr = currState->tc->readMiscReg(MISCREG_CPSR); currState->N = currState->tc->readMiscReg(MISCREG_TTBCR); currState->isFetch = (currState->mode == TLB::Execute); currState->isWrite = (currState->mode == TLB::Write); - currState->isPriv = (currState->cpsr.mode != MODE_USER); Addr ttbr = 0; diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 141bd7138..dc801dde8 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -60,7 +60,7 @@ class TLB; class TableWalker : public MemObject { - protected: + public: struct L1Descriptor { /** Type of page table entry ARM DDI 0406B: B3-8*/ enum EntryType { @@ -95,6 +95,14 @@ class TableWalker : public MemObject panic("Super sections not implemented\n"); return mbits(data, 31,20); } + /** Return the physcal address of the entry, bits in position*/ + Addr paddr(Addr va) const + { + if (supersection()) + panic("Super sections not implemented\n"); + return mbits(data, 31,20) | mbits(va, 20, 0); + } + /** Return the physical frame, bits shifted right */ Addr pfn() const @@ -220,6 +228,15 @@ class TableWalker : public MemObject return large() ? bits(data, 31, 16) : bits(data, 31, 12); } + /** Return complete physical address given a VA */ + Addr paddr(Addr va) const + { + if (large()) + return mbits(data, 31, 16) | mbits(va, 15, 0); + else + return mbits(data, 31, 12) | mbits(va, 11, 0); + } + /** If the section is shareable. See texcb() comment. */ bool shareable() const { @@ -266,18 +283,12 @@ class TableWalker : public MemObject /** Cached copy of the sctlr as it existed when translation began */ SCTLR sctlr; - /** Cached copy of the cpsr as it existed when the translation began */ - CPSR cpsr; - /** Width of the base address held in TTRB0 */ uint32_t N; /** If the access is a write */ bool isWrite; - /** If the access is not from user mode */ - bool isPriv; - /** If the access is a fetch (for execution, and no-exec) must be checked?*/ bool isFetch; diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index a48805c81..a8d78308f 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -84,8 +84,19 @@ TLB::~TLB() delete [] table; } +bool +TLB::translateFunctional(ThreadContext *tc, Addr va, Addr &pa) +{ + uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR); + TlbEntry *e = lookup(va, context_id, true); + if (!e) + return false; + pa = e->pAddr(va); + return true; +} + TlbEntry* -TLB::lookup(Addr va, uint8_t cid) +TLB::lookup(Addr va, uint8_t cid, bool functional) { // XXX This should either turn into a TlbMap or add caching @@ -97,7 +108,7 @@ TLB::lookup(Addr va, uint8_t cid) while (retval == NULL && x < size) { if (table[x].match(va, cid)) { retval = &table[x]; - if (x == nlu) + if (x == nlu && !functional) nextnlu(); break; diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index eec52d9d2..caccad873 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -97,7 +97,13 @@ class TLB : public BaseTLB #endif void nextnlu() { if (++nlu >= size) nlu = 0; } - TlbEntry *lookup(Addr vpn, uint8_t asn); + /** Lookup an entry in the TLB + * @param vpn virtual address + * @param asn context id/address space id to use + * @param functional if the lookup should modify state + * @return pointer to TLB entrry if it exists + */ + TlbEntry *lookup(Addr vpn, uint8_t asn, bool functional = false); // Access Stats mutable Stats::Scalar read_hits; @@ -154,6 +160,16 @@ class TLB : public BaseTLB static bool validVirtualAddress(Addr vaddr); + /** + * Do a functional lookup on the TLB (for debugging) + * and don't modify any internal state + * @param tc thread context to get the context id from + * @param vaddr virtual address to translate + * @param pa returned physical address + * @return if the translation was successful + */ + bool translateFunctional(ThreadContext *tc, Addr vaddr, Addr &paddr); + /** Accessor functions for memory attributes for last accessed TLB entry */ void diff --git a/src/arch/arm/vtophys.cc b/src/arch/arm/vtophys.cc index 01cbb3e79..1691a387c 100644 --- a/src/arch/arm/vtophys.cc +++ b/src/arch/arm/vtophys.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2010 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2007-2008 The Florida State University * All rights reserved. @@ -33,6 +45,8 @@ #include +#include "arch/arm/table_walker.hh" +#include "arch/arm/tlb.hh" #include "arch/arm/vtophys.hh" #include "base/chunk_generator.hh" #include "base/trace.hh" @@ -45,12 +59,80 @@ using namespace ArmISA; Addr ArmISA::vtophys(Addr vaddr) { - fatal("VTOPHYS: Can't convert vaddr to paddr on ARM without a thread context"); + fatal("VTOPHYS: Can't convert vaddr to paddr on ARM without a thread context"); } Addr ArmISA::vtophys(ThreadContext *tc, Addr addr) { - fatal("VTOPHYS: Unimplemented on ARM\n"); + SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR); + if (!sctlr.m) { + // Translation is currently disabled PA == VA + return addr; + } + bool success; + Addr pa; + ArmISA::TLB *tlb; + + // Check the TLBs far a translation + // It's possible that there is a validy translation in the tlb + // that is no loger valid in the page table in memory + // so we need to check here first + tlb = static_cast(tc->getDTBPtr()); + success = tlb->translateFunctional(tc, addr, pa); + if (success) + return pa; + + tlb = static_cast(tc->getITBPtr()); + success = tlb->translateFunctional(tc, addr, pa); + if (success) + return pa; + + // We've failed everything, so we need to do a + // hardware tlb walk without messing with any + // state + + uint32_t N = tc->readMiscReg(MISCREG_TTBCR); + Addr ttbr; + if (N == 0 || !mbits(addr, 31, 32-N)) { + ttbr = tc->readMiscReg(MISCREG_TTBR0); + } else { + ttbr = tc->readMiscReg(MISCREG_TTBR1); + N = 0; + } + + FunctionalPort *port = tc->getPhysPort(); + Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(addr,31-N,20) << 2); + + TableWalker::L1Descriptor l1desc; + l1desc.data = port->read(l1desc_addr); + if (l1desc.type() == TableWalker::L1Descriptor::Ignore || + l1desc.type() == TableWalker::L1Descriptor::Reserved) { + warn("Unable to translate virtual address: %#x\n", addr); + return -1; + } + if (l1desc.type() == TableWalker::L1Descriptor::Section) + return l1desc.paddr(addr); + + // Didn't find it at the first level, try againt + Addr l2desc_addr = l1desc.l2Addr() | (bits(addr, 19, 12) << 2); + TableWalker::L2Descriptor l2desc; + l2desc.data = port->read(l2desc_addr); + + if (l2desc.invalid()) { + warn("Unable to translate virtual address: %#x\n", addr); + return -1; + } + + return l2desc.paddr(addr); } +bool +ArmISA::virtvalid(ThreadContext *tc, Addr vaddr) +{ + if (vtophys(tc, vaddr) != -1) + return true; + return false; +} + + diff --git a/src/arch/arm/vtophys.hh b/src/arch/arm/vtophys.hh index 16d8c7ceb..12b4846ed 100644 --- a/src/arch/arm/vtophys.hh +++ b/src/arch/arm/vtophys.hh @@ -46,6 +46,7 @@ namespace ArmISA { Addr vtophys(Addr vaddr); Addr vtophys(ThreadContext *tc, Addr vaddr); + bool virtvalid(ThreadContext *tc, Addr vaddr); }; #endif // __ARCH_ARM_VTOPHYS_H__ -- cgit v1.2.3