tlb.cc revision 5288:7dd5694453b3
12SN/A/* 21762SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi 292665Ssaidi@eecs.umich.edu */ 302665Ssaidi@eecs.umich.edu 312SN/A#include <cstring> 322SN/A 332SN/A#include "arch/sparc/asi.hh" 342SN/A#include "arch/sparc/miscregfile.hh" 352SN/A#include "arch/sparc/tlb.hh" 362655Sstever@eecs.umich.edu#include "base/bitfield.hh" 372655Sstever@eecs.umich.edu#include "base/trace.hh" 382SN/A#include "cpu/thread_context.hh" 392SN/A#include "cpu/base.hh" 401399SN/A#include "mem/packet_access.hh" 411396SN/A#include "mem/request.hh" 422SN/A#include "sim/system.hh" 432SN/A 442729Ssaidi@eecs.umich.edu/* @todo remove some of the magic constants. -- ali 452SN/A * */ 461310SN/Anamespace SparcISA { 472SN/A 482SN/ATLB::TLB(const Params *p) 492SN/A : SimObject(p), size(p->size), usedEntries(0), lastReplaced(0), 502667Sstever@eecs.umich.edu cacheValid(false) 5156SN/A{ 52146SN/A // To make this work you'll have to change the hypervisor and OS 531388SN/A if (size > 64) 5456SN/A fatal("SPARC T1 TLB registers don't support more than 64 TLB entries."); 5556SN/A 561311SN/A tlb = new TlbEntry[size]; 57400SN/A std::memset(tlb, 0, sizeof(TlbEntry) * size); 581717SN/A 591717SN/A for (int x = 0; x < size; x++) 602738Sstever@eecs.umich.edu freeList.push_back(&tlb[x]); 612738Sstever@eecs.umich.edu 62146SN/A c0_tsb_ps0 = 0; 63146SN/A c0_tsb_ps1 = 0; 64146SN/A c0_config = 0; 652797Sktlim@umich.edu cx_tsb_ps0 = 0; 6656SN/A cx_tsb_ps1 = 0; 6756SN/A cx_config = 0; 6856SN/A sfsr = 0; 69695SN/A tag_access = 0; 70695SN/A} 711696SN/A 722SN/Avoid 732SN/ATLB::clearUsedBits() 742SN/A{ 752SN/A MapIter i; 762SN/A for (i = lookupTable.begin(); i != lookupTable.end(); i++) { 772SN/A TlbEntry *t = i->second; 78329SN/A if (!t->pte.locked()) { 792SN/A t->used = false; 802SN/A usedEntries--; 812SN/A } 822SN/A } 832SN/A} 842SN/A 852SN/A 862SN/Avoid 872SN/ATLB::insert(Addr va, int partition_id, int context_id, bool real, 882SN/A const PageTableEntry& PTE, int entry) 892SN/A{ 902SN/A 91329SN/A 92329SN/A MapIter i; 93329SN/A TlbEntry *new_entry = NULL; 94329SN/A// TlbRange tr; 95329SN/A int x; 96329SN/A 97329SN/A cacheValid = false; 982SN/A va &= ~(PTE.size()-1); 992SN/A /* tr.va = va; 1002SN/A tr.size = PTE.size() - 1; 1012SN/A tr.contextId = context_id; 1022SN/A tr.partitionId = partition_id; 1032SN/A tr.real = real; 1042SN/A*/ 1052SN/A 106764SN/A DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n", 107764SN/A va, PTE.paddr(), partition_id, context_id, (int)real, entry); 108764SN/A 109764SN/A // Demap any entry that conflicts 110764SN/A for (x = 0; x < size; x++) { 111764SN/A if (tlb[x].range.real == real && 112764SN/A tlb[x].range.partitionId == partition_id && 113764SN/A tlb[x].range.va < va + PTE.size() - 1 && 114764SN/A tlb[x].range.va + tlb[x].range.size >= va && 115764SN/A (real || tlb[x].range.contextId == context_id )) 116764SN/A { 117764SN/A if (tlb[x].valid) { 1182763Sstever@eecs.umich.edu freeList.push_front(&tlb[x]); 1192SN/A DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x); 1202SN/A 1212SN/A tlb[x].valid = false; 1222SN/A if (tlb[x].used) { 1232SN/A tlb[x].used = false; 1242SN/A usedEntries--; 125329SN/A } 126329SN/A lookupTable.erase(tlb[x].range); 127329SN/A } 128764SN/A } 1292SN/A } 1302655Sstever@eecs.umich.edu 1312667Sstever@eecs.umich.edu 1322667Sstever@eecs.umich.edu/* 1332889Sbinkertn@umich.edu i = lookupTable.find(tr); 1342889Sbinkertn@umich.edu if (i != lookupTable.end()) { 1352889Sbinkertn@umich.edu i->second->valid = false; 1362889Sbinkertn@umich.edu if (i->second->used) { 1372667Sstever@eecs.umich.edu i->second->used = false; 1382667Sstever@eecs.umich.edu usedEntries--; 1392667Sstever@eecs.umich.edu } 1402889Sbinkertn@umich.edu freeList.push_front(i->second); 1412889Sbinkertn@umich.edu DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n", 1422667Sstever@eecs.umich.edu i->second); 1432667Sstever@eecs.umich.edu lookupTable.erase(i); 1442889Sbinkertn@umich.edu } 1452667Sstever@eecs.umich.edu*/ 1462667Sstever@eecs.umich.edu 1472667Sstever@eecs.umich.edu if (entry != -1) { 1482655Sstever@eecs.umich.edu assert(entry < size && entry >= 0); 1492655Sstever@eecs.umich.edu new_entry = &tlb[entry]; 1501311SN/A } else { 1512763Sstever@eecs.umich.edu if (!freeList.empty()) { 1522763Sstever@eecs.umich.edu new_entry = freeList.front(); 1531703SN/A } else { 1542889Sbinkertn@umich.edu x = lastReplaced; 1552889Sbinkertn@umich.edu do { 1562667Sstever@eecs.umich.edu ++x; 1572667Sstever@eecs.umich.edu if (x == size) 1582655Sstever@eecs.umich.edu x = 0; 1592667Sstever@eecs.umich.edu if (x == lastReplaced) 1601388SN/A goto insertAllLocked; 1612762Sstever@eecs.umich.edu } while (tlb[x].pte.locked()); 1622762Sstever@eecs.umich.edu lastReplaced = x; 1632762Sstever@eecs.umich.edu new_entry = &tlb[x]; 1642762Sstever@eecs.umich.edu } 1652762Sstever@eecs.umich.edu /* 1662762Sstever@eecs.umich.edu for (x = 0; x < size; x++) { 1672762Sstever@eecs.umich.edu if (!tlb[x].valid || !tlb[x].used) { 1682762Sstever@eecs.umich.edu new_entry = &tlb[x]; 1692738Sstever@eecs.umich.edu break; 1702667Sstever@eecs.umich.edu } 1712738Sstever@eecs.umich.edu }*/ 1722738Sstever@eecs.umich.edu } 1732738Sstever@eecs.umich.edu 1742738Sstever@eecs.umich.eduinsertAllLocked: 1752738Sstever@eecs.umich.edu // Update the last ently if their all locked 1762738Sstever@eecs.umich.edu if (!new_entry) { 1772738Sstever@eecs.umich.edu new_entry = &tlb[size-1]; 1782738Sstever@eecs.umich.edu } 1792738Sstever@eecs.umich.edu 1802738Sstever@eecs.umich.edu freeList.remove(new_entry); 1812738Sstever@eecs.umich.edu if (new_entry->valid && new_entry->used) 1822738Sstever@eecs.umich.edu usedEntries--; 1832738Sstever@eecs.umich.edu if (new_entry->valid) 1842738Sstever@eecs.umich.edu lookupTable.erase(new_entry->range); 1852738Sstever@eecs.umich.edu 1862738Sstever@eecs.umich.edu 1872738Sstever@eecs.umich.edu assert(PTE.valid()); 1882738Sstever@eecs.umich.edu new_entry->range.va = va; 1892738Sstever@eecs.umich.edu new_entry->range.size = PTE.size() - 1; 1902738Sstever@eecs.umich.edu new_entry->range.partitionId = partition_id; 1912738Sstever@eecs.umich.edu new_entry->range.contextId = context_id; 1922738Sstever@eecs.umich.edu new_entry->range.real = real; 1932738Sstever@eecs.umich.edu new_entry->pte = PTE; 1942738Sstever@eecs.umich.edu new_entry->used = true;; 1952738Sstever@eecs.umich.edu new_entry->valid = true; 1962738Sstever@eecs.umich.edu usedEntries++; 1972738Sstever@eecs.umich.edu 1982738Sstever@eecs.umich.edu 1992738Sstever@eecs.umich.edu 2002738Sstever@eecs.umich.edu i = lookupTable.insert(new_entry->range, new_entry); 2012738Sstever@eecs.umich.edu assert(i != lookupTable.end()); 2022738Sstever@eecs.umich.edu 2032738Sstever@eecs.umich.edu // If all entries have there used bit set, clear it on them all, but the 2042738Sstever@eecs.umich.edu // one we just inserted 2052738Sstever@eecs.umich.edu if (usedEntries == size) { 2062738Sstever@eecs.umich.edu clearUsedBits(); 2072738Sstever@eecs.umich.edu new_entry->used = true; 2082738Sstever@eecs.umich.edu usedEntries++; 2092738Sstever@eecs.umich.edu } 2102738Sstever@eecs.umich.edu 2112667Sstever@eecs.umich.edu} 2122738Sstever@eecs.umich.edu 2132667Sstever@eecs.umich.edu 2142738Sstever@eecs.umich.eduTlbEntry* 2152655Sstever@eecs.umich.eduTLB::lookup(Addr va, int partition_id, bool real, int context_id, bool 2161388SN/A update_used) 2172SN/A{ 2182655Sstever@eecs.umich.edu MapIter i; 2192SN/A TlbRange tr; 2201388SN/A TlbEntry *t; 2211388SN/A 2222738Sstever@eecs.umich.edu DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n", 2232SN/A va, partition_id, context_id, real); 2241310SN/A // Assemble full address structure 2252738Sstever@eecs.umich.edu tr.va = va; 2262738Sstever@eecs.umich.edu tr.size = MachineBytes; 2272738Sstever@eecs.umich.edu tr.contextId = context_id; 2282738Sstever@eecs.umich.edu tr.partitionId = partition_id; 2292738Sstever@eecs.umich.edu tr.real = real; 2302738Sstever@eecs.umich.edu 2312738Sstever@eecs.umich.edu // Try to find the entry 2322738Sstever@eecs.umich.edu i = lookupTable.find(tr); 2332738Sstever@eecs.umich.edu if (i == lookupTable.end()) { 2342738Sstever@eecs.umich.edu DPRINTF(TLB, "TLB: No valid entry found\n"); 2352738Sstever@eecs.umich.edu return NULL; 2362738Sstever@eecs.umich.edu } 2372738Sstever@eecs.umich.edu 2382738Sstever@eecs.umich.edu // Mark the entries used bit and clear other used bits in needed 2392738Sstever@eecs.umich.edu t = i->second; 2402738Sstever@eecs.umich.edu DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(), 2412738Sstever@eecs.umich.edu t->pte.size()); 2422738Sstever@eecs.umich.edu 2432738Sstever@eecs.umich.edu // Update the used bits only if this is a real access (not a fake one from 2442738Sstever@eecs.umich.edu // virttophys() 2452738Sstever@eecs.umich.edu if (!t->used && update_used) { 2462738Sstever@eecs.umich.edu t->used = true; 2472738Sstever@eecs.umich.edu usedEntries++; 2482738Sstever@eecs.umich.edu if (usedEntries == size) { 2492738Sstever@eecs.umich.edu clearUsedBits(); 2502738Sstever@eecs.umich.edu t->used = true; 2512738Sstever@eecs.umich.edu usedEntries++; 2522738Sstever@eecs.umich.edu } 2532738Sstever@eecs.umich.edu } 2542738Sstever@eecs.umich.edu 2552738Sstever@eecs.umich.edu return t; 2562738Sstever@eecs.umich.edu} 2572738Sstever@eecs.umich.edu 2582738Sstever@eecs.umich.eduvoid 2592738Sstever@eecs.umich.eduTLB::dumpAll() 2602738Sstever@eecs.umich.edu{ 2612738Sstever@eecs.umich.edu MapIter i; 2622738Sstever@eecs.umich.edu for (int x = 0; x < size; x++) { 2632738Sstever@eecs.umich.edu if (tlb[x].valid) { 2642738Sstever@eecs.umich.edu DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n", 2652738Sstever@eecs.umich.edu x, tlb[x].range.partitionId, tlb[x].range.contextId, 2662738Sstever@eecs.umich.edu tlb[x].range.real ? 'R' : ' ', tlb[x].range.size, 2672738Sstever@eecs.umich.edu tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte()); 2682738Sstever@eecs.umich.edu } 2692738Sstever@eecs.umich.edu } 2702738Sstever@eecs.umich.edu} 2712738Sstever@eecs.umich.edu 2721388SN/Avoid 2731388SN/ATLB::demapPage(Addr va, int partition_id, bool real, int context_id) 2741388SN/A{ 2751388SN/A TlbRange tr; 2762667Sstever@eecs.umich.edu MapIter i; 2771104SN/A 2782SN/A DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n", 2791127SN/A va, partition_id, context_id, real); 2801127SN/A 2811127SN/A cacheValid = false; 2822SN/A 2832738Sstever@eecs.umich.edu // Assemble full address structure 2842SN/A tr.va = va; 2852738Sstever@eecs.umich.edu tr.size = MachineBytes; 2862SN/A tr.contextId = context_id; 2872SN/A tr.partitionId = partition_id; 2882SN/A tr.real = real; 2892SN/A 290729SN/A // Demap any entry that conflicts 2912SN/A i = lookupTable.find(tr); 292395SN/A if (i != lookupTable.end()) { 293729SN/A DPRINTF(IPR, "TLB: Demapped page\n"); 294395SN/A i->second->valid = false; 2951127SN/A if (i->second->used) { 2962667Sstever@eecs.umich.edu i->second->used = false; 2972667Sstever@eecs.umich.edu usedEntries--; 2982667Sstever@eecs.umich.edu } 2992667Sstever@eecs.umich.edu freeList.push_front(i->second); 3002667Sstever@eecs.umich.edu lookupTable.erase(i); 3012667Sstever@eecs.umich.edu } 3022667Sstever@eecs.umich.edu} 3032667Sstever@eecs.umich.edu 3042667Sstever@eecs.umich.eduvoid 3052667Sstever@eecs.umich.eduTLB::demapContext(int partition_id, int context_id) 3062667Sstever@eecs.umich.edu{ 3072667Sstever@eecs.umich.edu int x; 3082667Sstever@eecs.umich.edu DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n", 3092667Sstever@eecs.umich.edu partition_id, context_id); 3102667Sstever@eecs.umich.edu cacheValid = false; 3112667Sstever@eecs.umich.edu for (x = 0; x < size; x++) { 3122667Sstever@eecs.umich.edu if (tlb[x].range.contextId == context_id && 3132667Sstever@eecs.umich.edu tlb[x].range.partitionId == partition_id) { 3142667Sstever@eecs.umich.edu if (tlb[x].valid == true) { 3152667Sstever@eecs.umich.edu freeList.push_front(&tlb[x]); 3162667Sstever@eecs.umich.edu } 3172667Sstever@eecs.umich.edu tlb[x].valid = false; 3182667Sstever@eecs.umich.edu if (tlb[x].used) { 3192667Sstever@eecs.umich.edu tlb[x].used = false; 3202667Sstever@eecs.umich.edu usedEntries--; 3212667Sstever@eecs.umich.edu } 3222667Sstever@eecs.umich.edu lookupTable.erase(tlb[x].range); 3232667Sstever@eecs.umich.edu } 3242667Sstever@eecs.umich.edu } 3252667Sstever@eecs.umich.edu} 3262667Sstever@eecs.umich.edu 3272SN/Avoid 3282SN/ATLB::demapAll(int partition_id) 3292SN/A{ 3302SN/A int x; 3312SN/A DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id); 3322SN/A cacheValid = false; 3332667Sstever@eecs.umich.edu for (x = 0; x < size; x++) { 3342667Sstever@eecs.umich.edu if (tlb[x].valid && !tlb[x].pte.locked() && 3352667Sstever@eecs.umich.edu tlb[x].range.partitionId == partition_id) { 3362667Sstever@eecs.umich.edu freeList.push_front(&tlb[x]); 3372667Sstever@eecs.umich.edu tlb[x].valid = false; 3382667Sstever@eecs.umich.edu if (tlb[x].used) { 3392667Sstever@eecs.umich.edu tlb[x].used = false; 3402667Sstever@eecs.umich.edu usedEntries--; 3412667Sstever@eecs.umich.edu } 3422667Sstever@eecs.umich.edu lookupTable.erase(tlb[x].range); 3432667Sstever@eecs.umich.edu } 3442667Sstever@eecs.umich.edu } 3452667Sstever@eecs.umich.edu} 3462667Sstever@eecs.umich.edu 3472667Sstever@eecs.umich.eduvoid 3482667Sstever@eecs.umich.eduTLB::invalidateAll() 3492667Sstever@eecs.umich.edu{ 3502SN/A int x; 3512SN/A cacheValid = false; 3522SN/A 3532SN/A lookupTable.clear(); 3542SN/A for (x = 0; x < size; x++) { 355294SN/A if (tlb[x].valid == true) 356729SN/A freeList.push_back(&tlb[x]); 357294SN/A tlb[x].valid = false; 3582SN/A tlb[x].used = false; 3592SN/A } 360329SN/A usedEntries = 0; 361329SN/A} 362329SN/A 363729SN/Auint64_t 364329SN/ATLB::TteRead(int entry) { 365329SN/A if (entry >= size) 366329SN/A panic("entry: %d\n", entry); 3672SN/A 3682SN/A assert(entry < size); 3692667Sstever@eecs.umich.edu if (tlb[entry].valid) 3702SN/A return tlb[entry].pte(); 3712SN/A else 3722SN/A return (uint64_t)-1ll; 3732SN/A} 3742SN/A 3752SN/Auint64_t 3762SN/ATLB::TagRead(int entry) { 3772SN/A assert(entry < size); 3782SN/A uint64_t tag; 3792SN/A if (!tlb[entry].valid) 3802667Sstever@eecs.umich.edu return (uint64_t)-1ll; 3812667Sstever@eecs.umich.edu 3822SN/A tag = tlb[entry].range.contextId; 3832797Sktlim@umich.edu tag |= tlb[entry].range.va; 3842839Sktlim@umich.edu tag |= (uint64_t)tlb[entry].range.partitionId << 61; 3852797Sktlim@umich.edu tag |= tlb[entry].range.real ? ULL(1) << 60 : 0; 3862839Sktlim@umich.edu tag |= (uint64_t)~tlb[entry].pte._size() << 56; 3872797Sktlim@umich.edu return tag; 3882797Sktlim@umich.edu} 3892797Sktlim@umich.edu 3902839Sktlim@umich.edubool 3912797Sktlim@umich.eduTLB::validVirtualAddress(Addr va, bool am) 3922839Sktlim@umich.edu{ 3932839Sktlim@umich.edu if (am) 3942797Sktlim@umich.edu return true; 3952839Sktlim@umich.edu if (va >= StartVAddrHole && va <= EndVAddrHole) 3962839Sktlim@umich.edu return false; 3972797Sktlim@umich.edu return true; 3982797Sktlim@umich.edu} 3992797Sktlim@umich.edu 4002797Sktlim@umich.eduvoid 4012797Sktlim@umich.eduTLB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi) 4022797Sktlim@umich.edu{ 4032868Sktlim@umich.edu if (sfsr & 0x1) 4042797Sktlim@umich.edu sfsr = 0x3; 4052868Sktlim@umich.edu else 4062797Sktlim@umich.edu sfsr = 1; 4072797Sktlim@umich.edu 4082797Sktlim@umich.edu if (write) 4092868Sktlim@umich.edu sfsr |= 1 << 2; 4102797Sktlim@umich.edu sfsr |= ct << 4; 4112868Sktlim@umich.edu if (se) 4122797Sktlim@umich.edu sfsr |= 1 << 6; 4132797Sktlim@umich.edu sfsr |= ft << 7; 4142667Sstever@eecs.umich.edu sfsr |= asi << 16; 4152667Sstever@eecs.umich.edu} 4162667Sstever@eecs.umich.edu 4172667Sstever@eecs.umich.eduvoid 4182667Sstever@eecs.umich.eduTLB::writeTagAccess(Addr va, int context) 4192667Sstever@eecs.umich.edu{ 4202667Sstever@eecs.umich.edu DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n", 4212667Sstever@eecs.umich.edu va, context, mbits(va, 63,13) | mbits(context,12,0)); 4222667Sstever@eecs.umich.edu 4232667Sstever@eecs.umich.edu tag_access = mbits(va, 63,13) | mbits(context,12,0); 4242667Sstever@eecs.umich.edu} 4252667Sstever@eecs.umich.edu 4262SN/Avoid 4272667Sstever@eecs.umich.eduITB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi) 4282797Sktlim@umich.edu{ 4292797Sktlim@umich.edu DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n", 4302797Sktlim@umich.edu (int)write, ct, ft, asi); 4312797Sktlim@umich.edu TLB::writeSfsr(write, ct, se, ft, asi); 4322797Sktlim@umich.edu} 4332797Sktlim@umich.edu 4342797Sktlim@umich.eduvoid 4352797Sktlim@umich.eduDTB::writeSfsr(Addr a, bool write, ContextType ct, 4362797Sktlim@umich.edu bool se, FaultTypes ft, int asi) 4372797Sktlim@umich.edu{ 4382667Sstever@eecs.umich.edu DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n", 4392667Sstever@eecs.umich.edu a, (int)write, ct, ft, asi); 4402667Sstever@eecs.umich.edu TLB::writeSfsr(write, ct, se, ft, asi); 4412667Sstever@eecs.umich.edu sfar = a; 4422667Sstever@eecs.umich.edu} 4432667Sstever@eecs.umich.edu 4442667Sstever@eecs.umich.eduFault 4452667Sstever@eecs.umich.eduITB::translate(RequestPtr &req, ThreadContext *tc) 4462667Sstever@eecs.umich.edu{ 4472667Sstever@eecs.umich.edu uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); 4482667Sstever@eecs.umich.edu 4492667Sstever@eecs.umich.edu Addr vaddr = req->getVaddr(); 4502667Sstever@eecs.umich.edu TlbEntry *e; 4512667Sstever@eecs.umich.edu 4522667Sstever@eecs.umich.edu assert(req->getAsi() == ASI_IMPLICIT); 4532667Sstever@eecs.umich.edu 4542667Sstever@eecs.umich.edu DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n", 455 vaddr, req->getSize()); 456 457 // Be fast if we can! 458 if (cacheValid && cacheState == tlbdata) { 459 if (cacheEntry) { 460 if (cacheEntry->range.va < vaddr + sizeof(MachInst) && 461 cacheEntry->range.va + cacheEntry->range.size >= vaddr) { 462 req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) | 463 vaddr & cacheEntry->pte.size()-1 ); 464 return NoFault; 465 } 466 } else { 467 req->setPaddr(vaddr & PAddrImplMask); 468 return NoFault; 469 } 470 } 471 472 bool hpriv = bits(tlbdata,0,0); 473 bool red = bits(tlbdata,1,1); 474 bool priv = bits(tlbdata,2,2); 475 bool addr_mask = bits(tlbdata,3,3); 476 bool lsu_im = bits(tlbdata,4,4); 477 478 int part_id = bits(tlbdata,15,8); 479 int tl = bits(tlbdata,18,16); 480 int pri_context = bits(tlbdata,47,32); 481 int context; 482 ContextType ct; 483 int asi; 484 bool real = false; 485 486 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n", 487 priv, hpriv, red, lsu_im, part_id); 488 489 if (tl > 0) { 490 asi = ASI_N; 491 ct = Nucleus; 492 context = 0; 493 } else { 494 asi = ASI_P; 495 ct = Primary; 496 context = pri_context; 497 } 498 499 if ( hpriv || red ) { 500 cacheValid = true; 501 cacheState = tlbdata; 502 cacheEntry = NULL; 503 req->setPaddr(vaddr & PAddrImplMask); 504 return NoFault; 505 } 506 507 // If the access is unaligned trap 508 if (vaddr & 0x3) { 509 writeSfsr(false, ct, false, OtherFault, asi); 510 return new MemAddressNotAligned; 511 } 512 513 if (addr_mask) 514 vaddr = vaddr & VAddrAMask; 515 516 if (!validVirtualAddress(vaddr, addr_mask)) { 517 writeSfsr(false, ct, false, VaOutOfRange, asi); 518 return new InstructionAccessException; 519 } 520 521 if (!lsu_im) { 522 e = lookup(vaddr, part_id, true); 523 real = true; 524 context = 0; 525 } else { 526 e = lookup(vaddr, part_id, false, context); 527 } 528 529 if (e == NULL || !e->valid) { 530 writeTagAccess(vaddr, context); 531 if (real) 532 return new InstructionRealTranslationMiss; 533 else 534#if FULL_SYSTEM 535 return new FastInstructionAccessMMUMiss; 536#else 537 return new FastInstructionAccessMMUMiss(req->getVaddr()); 538#endif 539 } 540 541 // were not priviledged accesing priv page 542 if (!priv && e->pte.priv()) { 543 writeTagAccess(vaddr, context); 544 writeSfsr(false, ct, false, PrivViolation, asi); 545 return new InstructionAccessException; 546 } 547 548 // cache translation date for next translation 549 cacheValid = true; 550 cacheState = tlbdata; 551 cacheEntry = e; 552 553 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) | 554 vaddr & e->pte.size()-1 ); 555 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); 556 return NoFault; 557} 558 559 560 561Fault 562DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) 563{ 564 /* @todo this could really use some profiling and fixing to make it faster! */ 565 uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); 566 Addr vaddr = req->getVaddr(); 567 Addr size = req->getSize(); 568 ASI asi; 569 asi = (ASI)req->getAsi(); 570 bool implicit = false; 571 bool hpriv = bits(tlbdata,0,0); 572 bool unaligned = (vaddr & size-1); 573 574 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n", 575 vaddr, size, asi); 576 577 if (lookupTable.size() != 64 - freeList.size()) 578 panic("Lookup table size: %d tlb size: %d\n", lookupTable.size(), 579 freeList.size()); 580 if (asi == ASI_IMPLICIT) 581 implicit = true; 582 583 // Only use the fast path here if there doesn't need to be an unaligned 584 // trap later 585 if (!unaligned) { 586 if (hpriv && implicit) { 587 req->setPaddr(vaddr & PAddrImplMask); 588 return NoFault; 589 } 590 591 // Be fast if we can! 592 if (cacheValid && cacheState == tlbdata) { 593 594 595 596 if (cacheEntry[0]) { 597 TlbEntry *ce = cacheEntry[0]; 598 Addr ce_va = ce->range.va; 599 if (cacheAsi[0] == asi && 600 ce_va < vaddr + size && ce_va + ce->range.size > vaddr && 601 (!write || ce->pte.writable())) { 602 req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask()); 603 if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1) 604 req->setFlags(req->getFlags() | UNCACHEABLE); 605 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); 606 return NoFault; 607 } // if matched 608 } // if cache entry valid 609 if (cacheEntry[1]) { 610 TlbEntry *ce = cacheEntry[1]; 611 Addr ce_va = ce->range.va; 612 if (cacheAsi[1] == asi && 613 ce_va < vaddr + size && ce_va + ce->range.size > vaddr && 614 (!write || ce->pte.writable())) { 615 req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask()); 616 if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1) 617 req->setFlags(req->getFlags() | UNCACHEABLE); 618 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); 619 return NoFault; 620 } // if matched 621 } // if cache entry valid 622 } 623 } 624 625 bool red = bits(tlbdata,1,1); 626 bool priv = bits(tlbdata,2,2); 627 bool addr_mask = bits(tlbdata,3,3); 628 bool lsu_dm = bits(tlbdata,5,5); 629 630 int part_id = bits(tlbdata,15,8); 631 int tl = bits(tlbdata,18,16); 632 int pri_context = bits(tlbdata,47,32); 633 int sec_context = bits(tlbdata,63,48); 634 635 bool real = false; 636 ContextType ct = Primary; 637 int context = 0; 638 639 TlbEntry *e; 640 641 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n", 642 priv, hpriv, red, lsu_dm, part_id); 643 644 if (implicit) { 645 if (tl > 0) { 646 asi = ASI_N; 647 ct = Nucleus; 648 context = 0; 649 } else { 650 asi = ASI_P; 651 ct = Primary; 652 context = pri_context; 653 } 654 } else { 655 // We need to check for priv level/asi priv 656 if (!priv && !hpriv && !AsiIsUnPriv(asi)) { 657 // It appears that context should be Nucleus in these cases? 658 writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi); 659 return new PrivilegedAction; 660 } 661 662 if (!hpriv && AsiIsHPriv(asi)) { 663 writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi); 664 return new DataAccessException; 665 } 666 667 if (AsiIsPrimary(asi)) { 668 context = pri_context; 669 ct = Primary; 670 } else if (AsiIsSecondary(asi)) { 671 context = sec_context; 672 ct = Secondary; 673 } else if (AsiIsNucleus(asi)) { 674 ct = Nucleus; 675 context = 0; 676 } else { // ???? 677 ct = Primary; 678 context = pri_context; 679 } 680 } 681 682 if (!implicit && asi != ASI_P && asi != ASI_S) { 683 if (AsiIsLittle(asi)) 684 panic("Little Endian ASIs not supported\n"); 685 686 //XXX It's unclear from looking at the documentation how a no fault 687 //load differs from a regular one, other than what happens concerning 688 //nfo and e bits in the TTE 689// if (AsiIsNoFault(asi)) 690// panic("No Fault ASIs not supported\n"); 691 692 if (AsiIsPartialStore(asi)) 693 panic("Partial Store ASIs not supported\n"); 694 695 if (AsiIsCmt(asi)) 696 panic("Cmt ASI registers not implmented\n"); 697 698 if (AsiIsInterrupt(asi)) 699 goto handleIntRegAccess; 700 if (AsiIsMmu(asi)) 701 goto handleMmuRegAccess; 702 if (AsiIsScratchPad(asi)) 703 goto handleScratchRegAccess; 704 if (AsiIsQueue(asi)) 705 goto handleQueueRegAccess; 706 if (AsiIsSparcError(asi)) 707 goto handleSparcErrorRegAccess; 708 709 if (!AsiIsReal(asi) && !AsiIsNucleus(asi) && !AsiIsAsIfUser(asi) && 710 !AsiIsTwin(asi) && !AsiIsBlock(asi) && !AsiIsNoFault(asi)) 711 panic("Accessing ASI %#X. Should we?\n", asi); 712 } 713 714 // If the asi is unaligned trap 715 if (unaligned) { 716 writeSfsr(vaddr, false, ct, false, OtherFault, asi); 717 return new MemAddressNotAligned; 718 } 719 720 if (addr_mask) 721 vaddr = vaddr & VAddrAMask; 722 723 if (!validVirtualAddress(vaddr, addr_mask)) { 724 writeSfsr(vaddr, false, ct, true, VaOutOfRange, asi); 725 return new DataAccessException; 726 } 727 728 729 if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) { 730 real = true; 731 context = 0; 732 }; 733 734 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) { 735 req->setPaddr(vaddr & PAddrImplMask); 736 return NoFault; 737 } 738 739 e = lookup(vaddr, part_id, real, context); 740 741 if (e == NULL || !e->valid) { 742 writeTagAccess(vaddr, context); 743 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n"); 744 if (real) 745 return new DataRealTranslationMiss; 746 else 747#if FULL_SYSTEM 748 return new FastDataAccessMMUMiss; 749#else 750 return new FastDataAccessMMUMiss(req->getVaddr()); 751#endif 752 753 } 754 755 if (!priv && e->pte.priv()) { 756 writeTagAccess(vaddr, context); 757 writeSfsr(vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi); 758 return new DataAccessException; 759 } 760 761 if (write && !e->pte.writable()) { 762 writeTagAccess(vaddr, context); 763 writeSfsr(vaddr, write, ct, e->pte.sideffect(), OtherFault, asi); 764 return new FastDataAccessProtection; 765 } 766 767 if (e->pte.nofault() && !AsiIsNoFault(asi)) { 768 writeTagAccess(vaddr, context); 769 writeSfsr(vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi); 770 return new DataAccessException; 771 } 772 773 if (e->pte.sideffect() && AsiIsNoFault(asi)) { 774 writeTagAccess(vaddr, context); 775 writeSfsr(vaddr, write, ct, e->pte.sideffect(), SideEffect, asi); 776 return new DataAccessException; 777 } 778 779 780 if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1) 781 req->setFlags(req->getFlags() | UNCACHEABLE); 782 783 // cache translation date for next translation 784 cacheState = tlbdata; 785 if (!cacheValid) { 786 cacheEntry[1] = NULL; 787 cacheEntry[0] = NULL; 788 } 789 790 if (cacheEntry[0] != e && cacheEntry[1] != e) { 791 cacheEntry[1] = cacheEntry[0]; 792 cacheEntry[0] = e; 793 cacheAsi[1] = cacheAsi[0]; 794 cacheAsi[0] = asi; 795 if (implicit) 796 cacheAsi[0] = (ASI)0; 797 } 798 cacheValid = true; 799 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) | 800 vaddr & e->pte.size()-1); 801 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); 802 return NoFault; 803 804 /** Normal flow ends here. */ 805handleIntRegAccess: 806 if (!hpriv) { 807 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); 808 if (priv) 809 return new DataAccessException; 810 else 811 return new PrivilegedAction; 812 } 813 814 if (asi == ASI_SWVR_UDB_INTR_W && !write || 815 asi == ASI_SWVR_UDB_INTR_R && write) { 816 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); 817 return new DataAccessException; 818 } 819 820 goto regAccessOk; 821 822 823handleScratchRegAccess: 824 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) { 825 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); 826 return new DataAccessException; 827 } 828 goto regAccessOk; 829 830handleQueueRegAccess: 831 if (!priv && !hpriv) { 832 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); 833 return new PrivilegedAction; 834 } 835 if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) { 836 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); 837 return new DataAccessException; 838 } 839 goto regAccessOk; 840 841handleSparcErrorRegAccess: 842 if (!hpriv) { 843 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); 844 if (priv) 845 return new DataAccessException; 846 else 847 return new PrivilegedAction; 848 } 849 goto regAccessOk; 850 851 852regAccessOk: 853handleMmuRegAccess: 854 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n"); 855 req->setMmapedIpr(true); 856 req->setPaddr(req->getVaddr()); 857 return NoFault; 858}; 859 860#if FULL_SYSTEM 861 862Tick 863DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) 864{ 865 Addr va = pkt->getAddr(); 866 ASI asi = (ASI)pkt->req->getAsi(); 867 uint64_t temp; 868 869 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n", 870 (uint32_t)pkt->req->getAsi(), pkt->getAddr()); 871 872 ITB * itb = tc->getITBPtr(); 873 874 switch (asi) { 875 case ASI_LSU_CONTROL_REG: 876 assert(va == 0); 877 pkt->set(tc->readMiscReg(MISCREG_MMU_LSU_CTRL)); 878 break; 879 case ASI_MMU: 880 switch (va) { 881 case 0x8: 882 pkt->set(tc->readMiscReg(MISCREG_MMU_P_CONTEXT)); 883 break; 884 case 0x10: 885 pkt->set(tc->readMiscReg(MISCREG_MMU_S_CONTEXT)); 886 break; 887 default: 888 goto doMmuReadError; 889 } 890 break; 891 case ASI_QUEUE: 892 pkt->set(tc->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD + 893 (va >> 4) - 0x3c)); 894 break; 895 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0: 896 assert(va == 0); 897 pkt->set(c0_tsb_ps0); 898 break; 899 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1: 900 assert(va == 0); 901 pkt->set(c0_tsb_ps1); 902 break; 903 case ASI_DMMU_CTXT_ZERO_CONFIG: 904 assert(va == 0); 905 pkt->set(c0_config); 906 break; 907 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0: 908 assert(va == 0); 909 pkt->set(itb->c0_tsb_ps0); 910 break; 911 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1: 912 assert(va == 0); 913 pkt->set(itb->c0_tsb_ps1); 914 break; 915 case ASI_IMMU_CTXT_ZERO_CONFIG: 916 assert(va == 0); 917 pkt->set(itb->c0_config); 918 break; 919 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0: 920 assert(va == 0); 921 pkt->set(cx_tsb_ps0); 922 break; 923 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1: 924 assert(va == 0); 925 pkt->set(cx_tsb_ps1); 926 break; 927 case ASI_DMMU_CTXT_NONZERO_CONFIG: 928 assert(va == 0); 929 pkt->set(cx_config); 930 break; 931 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0: 932 assert(va == 0); 933 pkt->set(itb->cx_tsb_ps0); 934 break; 935 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1: 936 assert(va == 0); 937 pkt->set(itb->cx_tsb_ps1); 938 break; 939 case ASI_IMMU_CTXT_NONZERO_CONFIG: 940 assert(va == 0); 941 pkt->set(itb->cx_config); 942 break; 943 case ASI_SPARC_ERROR_STATUS_REG: 944 pkt->set((uint64_t)0); 945 break; 946 case ASI_HYP_SCRATCHPAD: 947 case ASI_SCRATCHPAD: 948 pkt->set(tc->readMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3))); 949 break; 950 case ASI_IMMU: 951 switch (va) { 952 case 0x0: 953 temp = itb->tag_access; 954 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); 955 break; 956 case 0x18: 957 pkt->set(itb->sfsr); 958 break; 959 case 0x30: 960 pkt->set(itb->tag_access); 961 break; 962 default: 963 goto doMmuReadError; 964 } 965 break; 966 case ASI_DMMU: 967 switch (va) { 968 case 0x0: 969 temp = tag_access; 970 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); 971 break; 972 case 0x18: 973 pkt->set(sfsr); 974 break; 975 case 0x20: 976 pkt->set(sfar); 977 break; 978 case 0x30: 979 pkt->set(tag_access); 980 break; 981 case 0x80: 982 pkt->set(tc->readMiscReg(MISCREG_MMU_PART_ID)); 983 break; 984 default: 985 goto doMmuReadError; 986 } 987 break; 988 case ASI_DMMU_TSB_PS0_PTR_REG: 989 pkt->set(MakeTsbPtr(Ps0, 990 tag_access, 991 c0_tsb_ps0, 992 c0_config, 993 cx_tsb_ps0, 994 cx_config)); 995 break; 996 case ASI_DMMU_TSB_PS1_PTR_REG: 997 pkt->set(MakeTsbPtr(Ps1, 998 tag_access, 999 c0_tsb_ps1, 1000 c0_config, 1001 cx_tsb_ps1, 1002 cx_config)); 1003 break; 1004 case ASI_IMMU_TSB_PS0_PTR_REG: 1005 pkt->set(MakeTsbPtr(Ps0, 1006 itb->tag_access, 1007 itb->c0_tsb_ps0, 1008 itb->c0_config, 1009 itb->cx_tsb_ps0, 1010 itb->cx_config)); 1011 break; 1012 case ASI_IMMU_TSB_PS1_PTR_REG: 1013 pkt->set(MakeTsbPtr(Ps1, 1014 itb->tag_access, 1015 itb->c0_tsb_ps1, 1016 itb->c0_config, 1017 itb->cx_tsb_ps1, 1018 itb->cx_config)); 1019 break; 1020 case ASI_SWVR_INTR_RECEIVE: 1021 pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC)); 1022 break; 1023 case ASI_SWVR_UDB_INTR_R: 1024 temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC)); 1025 tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp); 1026 pkt->set(temp); 1027 break; 1028 default: 1029doMmuReadError: 1030 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n", 1031 (uint32_t)asi, va); 1032 } 1033 pkt->makeAtomicResponse(); 1034 return tc->getCpuPtr()->ticks(1); 1035} 1036 1037Tick 1038DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) 1039{ 1040 uint64_t data = gtoh(pkt->get<uint64_t>()); 1041 Addr va = pkt->getAddr(); 1042 ASI asi = (ASI)pkt->req->getAsi(); 1043 1044 Addr ta_insert; 1045 Addr va_insert; 1046 Addr ct_insert; 1047 int part_insert; 1048 int entry_insert = -1; 1049 bool real_insert; 1050 bool ignore; 1051 int part_id; 1052 int ctx_id; 1053 PageTableEntry pte; 1054 1055 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n", 1056 (uint32_t)asi, va, data); 1057 1058 ITB * itb = tc->getITBPtr(); 1059 1060 switch (asi) { 1061 case ASI_LSU_CONTROL_REG: 1062 assert(va == 0); 1063 tc->setMiscReg(MISCREG_MMU_LSU_CTRL, data); 1064 break; 1065 case ASI_MMU: 1066 switch (va) { 1067 case 0x8: 1068 tc->setMiscReg(MISCREG_MMU_P_CONTEXT, data); 1069 break; 1070 case 0x10: 1071 tc->setMiscReg(MISCREG_MMU_S_CONTEXT, data); 1072 break; 1073 default: 1074 goto doMmuWriteError; 1075 } 1076 break; 1077 case ASI_QUEUE: 1078 assert(mbits(data,13,6) == data); 1079 tc->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD + 1080 (va >> 4) - 0x3c, data); 1081 break; 1082 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0: 1083 assert(va == 0); 1084 c0_tsb_ps0 = data; 1085 break; 1086 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1: 1087 assert(va == 0); 1088 c0_tsb_ps1 = data; 1089 break; 1090 case ASI_DMMU_CTXT_ZERO_CONFIG: 1091 assert(va == 0); 1092 c0_config = data; 1093 break; 1094 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0: 1095 assert(va == 0); 1096 itb->c0_tsb_ps0 = data; 1097 break; 1098 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1: 1099 assert(va == 0); 1100 itb->c0_tsb_ps1 = data; 1101 break; 1102 case ASI_IMMU_CTXT_ZERO_CONFIG: 1103 assert(va == 0); 1104 itb->c0_config = data; 1105 break; 1106 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0: 1107 assert(va == 0); 1108 cx_tsb_ps0 = data; 1109 break; 1110 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1: 1111 assert(va == 0); 1112 cx_tsb_ps1 = data; 1113 break; 1114 case ASI_DMMU_CTXT_NONZERO_CONFIG: 1115 assert(va == 0); 1116 cx_config = data; 1117 break; 1118 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0: 1119 assert(va == 0); 1120 itb->cx_tsb_ps0 = data; 1121 break; 1122 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1: 1123 assert(va == 0); 1124 itb->cx_tsb_ps1 = data; 1125 break; 1126 case ASI_IMMU_CTXT_NONZERO_CONFIG: 1127 assert(va == 0); 1128 itb->cx_config = data; 1129 break; 1130 case ASI_SPARC_ERROR_EN_REG: 1131 case ASI_SPARC_ERROR_STATUS_REG: 1132 warn("Ignoring write to SPARC ERROR regsiter\n"); 1133 break; 1134 case ASI_HYP_SCRATCHPAD: 1135 case ASI_SCRATCHPAD: 1136 tc->setMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3), data); 1137 break; 1138 case ASI_IMMU: 1139 switch (va) { 1140 case 0x18: 1141 itb->sfsr = data; 1142 break; 1143 case 0x30: 1144 sext<59>(bits(data, 59,0)); 1145 itb->tag_access = data; 1146 break; 1147 default: 1148 goto doMmuWriteError; 1149 } 1150 break; 1151 case ASI_ITLB_DATA_ACCESS_REG: 1152 entry_insert = bits(va, 8,3); 1153 case ASI_ITLB_DATA_IN_REG: 1154 assert(entry_insert != -1 || mbits(va,10,9) == va); 1155 ta_insert = itb->tag_access; 1156 va_insert = mbits(ta_insert, 63,13); 1157 ct_insert = mbits(ta_insert, 12,0); 1158 part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID); 1159 real_insert = bits(va, 9,9); 1160 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v : 1161 PageTableEntry::sun4u); 1162 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert, 1163 pte, entry_insert); 1164 break; 1165 case ASI_DTLB_DATA_ACCESS_REG: 1166 entry_insert = bits(va, 8,3); 1167 case ASI_DTLB_DATA_IN_REG: 1168 assert(entry_insert != -1 || mbits(va,10,9) == va); 1169 ta_insert = tag_access; 1170 va_insert = mbits(ta_insert, 63,13); 1171 ct_insert = mbits(ta_insert, 12,0); 1172 part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID); 1173 real_insert = bits(va, 9,9); 1174 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v : 1175 PageTableEntry::sun4u); 1176 insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert); 1177 break; 1178 case ASI_IMMU_DEMAP: 1179 ignore = false; 1180 ctx_id = -1; 1181 part_id = tc->readMiscReg(MISCREG_MMU_PART_ID); 1182 switch (bits(va,5,4)) { 1183 case 0: 1184 ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT); 1185 break; 1186 case 1: 1187 ignore = true; 1188 break; 1189 case 3: 1190 ctx_id = 0; 1191 break; 1192 default: 1193 ignore = true; 1194 } 1195 1196 switch(bits(va,7,6)) { 1197 case 0: // demap page 1198 if (!ignore) 1199 tc->getITBPtr()->demapPage(mbits(va,63,13), part_id, 1200 bits(va,9,9), ctx_id); 1201 break; 1202 case 1: //demap context 1203 if (!ignore) 1204 tc->getITBPtr()->demapContext(part_id, ctx_id); 1205 break; 1206 case 2: 1207 tc->getITBPtr()->demapAll(part_id); 1208 break; 1209 default: 1210 panic("Invalid type for IMMU demap\n"); 1211 } 1212 break; 1213 case ASI_DMMU: 1214 switch (va) { 1215 case 0x18: 1216 sfsr = data; 1217 break; 1218 case 0x30: 1219 sext<59>(bits(data, 59,0)); 1220 tag_access = data; 1221 break; 1222 case 0x80: 1223 tc->setMiscReg(MISCREG_MMU_PART_ID, data); 1224 break; 1225 default: 1226 goto doMmuWriteError; 1227 } 1228 break; 1229 case ASI_DMMU_DEMAP: 1230 ignore = false; 1231 ctx_id = -1; 1232 part_id = tc->readMiscReg(MISCREG_MMU_PART_ID); 1233 switch (bits(va,5,4)) { 1234 case 0: 1235 ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT); 1236 break; 1237 case 1: 1238 ctx_id = tc->readMiscReg(MISCREG_MMU_S_CONTEXT); 1239 break; 1240 case 3: 1241 ctx_id = 0; 1242 break; 1243 default: 1244 ignore = true; 1245 } 1246 1247 switch(bits(va,7,6)) { 1248 case 0: // demap page 1249 if (!ignore) 1250 demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id); 1251 break; 1252 case 1: //demap context 1253 if (!ignore) 1254 demapContext(part_id, ctx_id); 1255 break; 1256 case 2: 1257 demapAll(part_id); 1258 break; 1259 default: 1260 panic("Invalid type for IMMU demap\n"); 1261 } 1262 break; 1263 case ASI_SWVR_INTR_RECEIVE: 1264 int msb; 1265 // clear all the interrupts that aren't set in the write 1266 while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) { 1267 msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data); 1268 tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb); 1269 } 1270 break; 1271 case ASI_SWVR_UDB_INTR_W: 1272 tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()-> 1273 post_interrupt(bits(data,5,0),0); 1274 break; 1275 default: 1276doMmuWriteError: 1277 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n", 1278 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data); 1279 } 1280 pkt->makeAtomicResponse(); 1281 return tc->getCpuPtr()->ticks(1); 1282} 1283 1284#endif 1285 1286void 1287DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs) 1288{ 1289 uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0); 1290 ITB * itb = tc->getITBPtr(); 1291 ptrs[0] = MakeTsbPtr(Ps0, tag_access, 1292 c0_tsb_ps0, 1293 c0_config, 1294 cx_tsb_ps0, 1295 cx_config); 1296 ptrs[1] = MakeTsbPtr(Ps1, tag_access, 1297 c0_tsb_ps1, 1298 c0_config, 1299 cx_tsb_ps1, 1300 cx_config); 1301 ptrs[2] = MakeTsbPtr(Ps0, tag_access, 1302 itb->c0_tsb_ps0, 1303 itb->c0_config, 1304 itb->cx_tsb_ps0, 1305 itb->cx_config); 1306 ptrs[3] = MakeTsbPtr(Ps1, tag_access, 1307 itb->c0_tsb_ps1, 1308 itb->c0_config, 1309 itb->cx_tsb_ps1, 1310 itb->cx_config); 1311} 1312 1313 1314 1315 1316 1317uint64_t 1318DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb, 1319 uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config) 1320{ 1321 uint64_t tsb; 1322 uint64_t config; 1323 1324 if (bits(tag_access, 12,0) == 0) { 1325 tsb = c0_tsb; 1326 config = c0_config; 1327 } else { 1328 tsb = cX_tsb; 1329 config = cX_config; 1330 } 1331 1332 uint64_t ptr = mbits(tsb,63,13); 1333 bool split = bits(tsb,12,12); 1334 int tsb_size = bits(tsb,3,0); 1335 int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8); 1336 1337 if (ps == Ps1 && split) 1338 ptr |= ULL(1) << (13 + tsb_size); 1339 ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4); 1340 1341 return ptr; 1342} 1343 1344 1345void 1346TLB::serialize(std::ostream &os) 1347{ 1348 SERIALIZE_SCALAR(size); 1349 SERIALIZE_SCALAR(usedEntries); 1350 SERIALIZE_SCALAR(lastReplaced); 1351 1352 // convert the pointer based free list into an index based one 1353 int *free_list = (int*)malloc(sizeof(int) * size); 1354 int cntr = 0; 1355 std::list<TlbEntry*>::iterator i; 1356 i = freeList.begin(); 1357 while (i != freeList.end()) { 1358 free_list[cntr++] = ((size_t)*i - (size_t)tlb)/ sizeof(TlbEntry); 1359 i++; 1360 } 1361 SERIALIZE_SCALAR(cntr); 1362 SERIALIZE_ARRAY(free_list, cntr); 1363 1364 SERIALIZE_SCALAR(c0_tsb_ps0); 1365 SERIALIZE_SCALAR(c0_tsb_ps1); 1366 SERIALIZE_SCALAR(c0_config); 1367 SERIALIZE_SCALAR(cx_tsb_ps0); 1368 SERIALIZE_SCALAR(cx_tsb_ps1); 1369 SERIALIZE_SCALAR(cx_config); 1370 SERIALIZE_SCALAR(sfsr); 1371 SERIALIZE_SCALAR(tag_access); 1372 1373 for (int x = 0; x < size; x++) { 1374 nameOut(os, csprintf("%s.PTE%d", name(), x)); 1375 tlb[x].serialize(os); 1376 } 1377} 1378 1379void 1380TLB::unserialize(Checkpoint *cp, const std::string §ion) 1381{ 1382 int oldSize; 1383 1384 paramIn(cp, section, "size", oldSize); 1385 if (oldSize != size) 1386 panic("Don't support unserializing different sized TLBs\n"); 1387 UNSERIALIZE_SCALAR(usedEntries); 1388 UNSERIALIZE_SCALAR(lastReplaced); 1389 1390 int cntr; 1391 UNSERIALIZE_SCALAR(cntr); 1392 1393 int *free_list = (int*)malloc(sizeof(int) * cntr); 1394 freeList.clear(); 1395 UNSERIALIZE_ARRAY(free_list, cntr); 1396 for (int x = 0; x < cntr; x++) 1397 freeList.push_back(&tlb[free_list[x]]); 1398 1399 UNSERIALIZE_SCALAR(c0_tsb_ps0); 1400 UNSERIALIZE_SCALAR(c0_tsb_ps1); 1401 UNSERIALIZE_SCALAR(c0_config); 1402 UNSERIALIZE_SCALAR(cx_tsb_ps0); 1403 UNSERIALIZE_SCALAR(cx_tsb_ps1); 1404 UNSERIALIZE_SCALAR(cx_config); 1405 UNSERIALIZE_SCALAR(sfsr); 1406 UNSERIALIZE_SCALAR(tag_access); 1407 1408 lookupTable.clear(); 1409 for (int x = 0; x < size; x++) { 1410 tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x)); 1411 if (tlb[x].valid) 1412 lookupTable.insert(tlb[x].range, &tlb[x]); 1413 1414 } 1415} 1416 1417void 1418DTB::serialize(std::ostream &os) 1419{ 1420 TLB::serialize(os); 1421 SERIALIZE_SCALAR(sfar); 1422} 1423 1424void 1425DTB::unserialize(Checkpoint *cp, const std::string §ion) 1426{ 1427 TLB::unserialize(cp, section); 1428 UNSERIALIZE_SCALAR(sfar); 1429} 1430 1431/* end namespace SparcISA */ } 1432 1433SparcISA::ITB * 1434SparcITBParams::create() 1435{ 1436 return new SparcISA::ITB(this); 1437} 1438 1439SparcISA::DTB * 1440SparcDTBParams::create() 1441{ 1442 return new SparcISA::DTB(this); 1443} 1444