m_transtab.c revision 5d0d1f3a78d6c5c765360982a08d87a068ce7f1c
1de4a1d01951937632098a6cda45859afa587a06fsewardj
2de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
3de4a1d01951937632098a6cda45859afa587a06fsewardj/*--- Management of the translation table and cache.               ---*/
48bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn/*---                                                 m_transtab.c ---*/
5de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
6de4a1d01951937632098a6cda45859afa587a06fsewardj
7de4a1d01951937632098a6cda45859afa587a06fsewardj/*
8b9c427c63a278cc612ae0ec573be7bb1abaa447fnjn   This file is part of Valgrind, a dynamic binary instrumentation
9b9c427c63a278cc612ae0ec573be7bb1abaa447fnjn   framework.
10de4a1d01951937632098a6cda45859afa587a06fsewardj
119f207460d70d38c46c9e81996a3dcdf90961c6dbnjn   Copyright (C) 2000-2009 Julian Seward
12de4a1d01951937632098a6cda45859afa587a06fsewardj      jseward@acm.org
13de4a1d01951937632098a6cda45859afa587a06fsewardj
14de4a1d01951937632098a6cda45859afa587a06fsewardj   This program is free software; you can redistribute it and/or
15de4a1d01951937632098a6cda45859afa587a06fsewardj   modify it under the terms of the GNU General Public License as
16de4a1d01951937632098a6cda45859afa587a06fsewardj   published by the Free Software Foundation; either version 2 of the
17de4a1d01951937632098a6cda45859afa587a06fsewardj   License, or (at your option) any later version.
18de4a1d01951937632098a6cda45859afa587a06fsewardj
19de4a1d01951937632098a6cda45859afa587a06fsewardj   This program is distributed in the hope that it will be useful, but
20de4a1d01951937632098a6cda45859afa587a06fsewardj   WITHOUT ANY WARRANTY; without even the implied warranty of
21de4a1d01951937632098a6cda45859afa587a06fsewardj   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22de4a1d01951937632098a6cda45859afa587a06fsewardj   General Public License for more details.
23de4a1d01951937632098a6cda45859afa587a06fsewardj
24de4a1d01951937632098a6cda45859afa587a06fsewardj   You should have received a copy of the GNU General Public License
25de4a1d01951937632098a6cda45859afa587a06fsewardj   along with this program; if not, write to the Free Software
26de4a1d01951937632098a6cda45859afa587a06fsewardj   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27de4a1d01951937632098a6cda45859afa587a06fsewardj   02111-1307, USA.
28de4a1d01951937632098a6cda45859afa587a06fsewardj
29e49d8e7dfd3a9c96feb9935b5920973dfc0b170anjn   The GNU General Public License is contained in the file COPYING.
30de4a1d01951937632098a6cda45859afa587a06fsewardj*/
31de4a1d01951937632098a6cda45859afa587a06fsewardj
32c7561b931e249acf3768ead77638545b0ccaa8f1njn#include "pub_core_basics.h"
3345f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include "pub_core_debuglog.h"
341f0d814045aba94e01e62e04e968ca8b970b3d44cerion#include "pub_core_machine.h"    // For VG(machine_get_VexArchInfo)
3597405b2d134b52880d6dbec3eb2929e2002c2542njn#include "pub_core_libcbase.h"
36132bfccd21960e462352175f8553a5bdce8a210cnjn#include "pub_core_libcassert.h"
3736a20fa5f779a0a6fb7b4a90dcaa6376481f1faanjn#include "pub_core_libcprint.h"
382024234c590f408994b373abfb00bc2cd2a90c48njn#include "pub_core_options.h"
3910f08cf5b84882eebbb6712a7be890577650e8adsewardj#include "pub_core_tooliface.h"  // For VG_(details).avg_translation_sizeB
408bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn#include "pub_core_transtab.h"
4145f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include "pub_core_aspacemgr.h"
4245f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include "pub_core_mallocfree.h" // VG_(out_of_memory_NORETURN)
43de4a1d01951937632098a6cda45859afa587a06fsewardj
4459570ffbe31930ab4d678754daaeec0715117a3dsewardj// JRS FIXME get rid of this somehow
4559570ffbe31930ab4d678754daaeec0715117a3dsewardj#if defined(VGP_arm_linux)
4659570ffbe31930ab4d678754daaeec0715117a3dsewardj# include "pub_core_vkiscnums.h" // __ARM_NR_cacheflush
4759570ffbe31930ab4d678754daaeec0715117a3dsewardj# include "pub_core_syscall.h"   // VG_(do_syscallN)
4859570ffbe31930ab4d678754daaeec0715117a3dsewardj#endif
4959570ffbe31930ab4d678754daaeec0715117a3dsewardj
5059570ffbe31930ab4d678754daaeec0715117a3dsewardj
5118d7513cc08bf982711c8a22b70d56af6aa87b33sewardj/* #define DEBUG_TRANSTAB */
5218d7513cc08bf982711c8a22b70d56af6aa87b33sewardj
53de4a1d01951937632098a6cda45859afa587a06fsewardj
546c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*-------------------------------------------------------------*/
556c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*--- Management of the FIFO-based translation table+cache. ---*/
566c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*-------------------------------------------------------------*/
57de4a1d01951937632098a6cda45859afa587a06fsewardj
586c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*------------------ CONSTANTS ------------------*/
59de4a1d01951937632098a6cda45859afa587a06fsewardj
60fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of sectors the TC is divided into.  If you need a larger
61fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   overall translation cache, increase this value. */
62fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj#define N_SECTORS 8
63de4a1d01951937632098a6cda45859afa587a06fsewardj
64fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of TC entries in each sector.  This needs to be a prime
656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   number to work properly, it must be <= 65535 (so that a TT index
666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   fits in a UShort, leaving room for 0xFFFF(EC2TTE_DELETED) to denote
676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   'deleted') and it is strongly recommended not to change this.
686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   65521 is the largest prime <= 65535. */
696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#define N_TTES_PER_SECTOR /*30011*/ /*40009*/ 65521
70de4a1d01951937632098a6cda45859afa587a06fsewardj
71fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Because each sector contains a hash table of TTEntries, we need to
72fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   specify the maximum allowable loading, after which the sector is
73fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   deemed full. */
745d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj#define SECTOR_TT_LIMIT_PERCENT 65
75de4a1d01951937632098a6cda45859afa587a06fsewardj
76fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* The sector is deemed full when this many entries are in it. */
77fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj#define N_TTES_PER_SECTOR_USABLE \
78fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj           ((N_TTES_PER_SECTOR * SECTOR_TT_LIMIT_PERCENT) / 100)
796c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
806c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Equivalence classes for fast address range deletion.  There are 1 +
816c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   2^ECLASS_WIDTH bins.  The highest one, ECLASS_MISC, describes an
826c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   address range which does not fall cleanly within any specific bin.
836c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Note that ECLASS_SHIFT + ECLASS_WIDTH must be < 32. */
846c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#define ECLASS_SHIFT 11
856c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#define ECLASS_WIDTH 8
866c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#define ECLASS_MISC  (1 << ECLASS_WIDTH)
876c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#define ECLASS_N     (1 + ECLASS_MISC)
886c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
896c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#define EC2TTE_DELETED  0xFFFF /* 16-bit special value */
906c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
91de4a1d01951937632098a6cda45859afa587a06fsewardj
926c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*------------------ TYPES ------------------*/
93de4a1d01951937632098a6cda45859afa587a06fsewardj
94fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* A translation-table entry.  This indicates precisely which areas of
95fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   guest code are included in the translation, and contains all other
96fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   auxiliary info too.  */
976c3769f487145a08c01b58d6e5db3ba274062ad4sewardjtypedef
986c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   struct {
99fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Profiling only: the count and weight (arbitrary meaning) for
100fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         this translation.  Weight is a property of the translation
101fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         itself and computed once when the translation is created.
102fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         Count is an entry count for the translation and is
103fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         incremented by 1 every time the translation is used, if we
104fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         are profiling. */
105fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      UInt     count;
106fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      UShort   weight;
107fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
108fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Status of the slot.  Note, we need to be able to do lazy
109fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         deletion, hence the Deleted state. */
110fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      enum { InUse, Deleted, Empty } status;
111fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1125f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      /* 64-bit aligned pointer to one or more 64-bit words containing
1135f76de086a6d643db51e50a4e623df7dfc9b6161sewardj         the corresponding host code (must be in the same sector!)
1145f76de086a6d643db51e50a4e623df7dfc9b6161sewardj         This is a pointer into the sector's tc (code) area. */
1155f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      ULong* tcptr;
116fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
117fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* This is the original guest address that purportedly is the
118fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         entry point of the translation.  You might think that .entry
119fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         should be the same as .vge->base[0], and most of the time it
120fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         is.  However, when doing redirections, that is not the case.
121fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         .vge must always correctly describe the guest code sections
122fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         from which this translation was made.  However, .entry may or
123fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         may not be a lie, depending on whether or not we're doing
124fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         redirection. */
125fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      Addr64 entry;
126fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
127fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* This structure describes precisely what ranges of guest code
128fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         the translation covers, so we can decide whether or not to
129fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         delete it when translations of a given address range are
130fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         invalidated. */
131fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VexGuestExtents vge;
1326c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
1336c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* Address range summary info: these are pointers back to
1346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         eclass[] entries in the containing Sector.  Those entries in
1356c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         turn point back here -- the two structures are mutually
1366c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         redundant but both necessary to make fast deletions work.
1376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         The eclass info is similar to, and derived from, this entry's
1386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         'vge' field, but it is not the same */
1396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      UShort n_tte2ec;      // # tte2ec pointers (1 to 3)
1406c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      UShort tte2ec_ec[3];  // for each, the eclass #
1416c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      UInt   tte2ec_ix[3];  // and the index within the eclass.
1426c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      // for i in 0 .. n_tte2ec-1
1436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      //    sec->ec2tte[ tte2ec_ec[i] ][ tte2ec_ix[i] ]
1446c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      // should be the index
1456c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      // of this TTEntry in the containing Sector's tt array.
1466c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
1476c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   TTEntry;
1486c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
1494ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
150fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Finally, a sector itself.  Each sector contains an array of
151fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   TCEntries, which hold code, and an array of TTEntries, containing
152fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   all required administrative info.  Profiling is supported using the
153fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   TTEntry .count and .weight fields, if required.  Each sector is
154fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   independent in that no cross-sector references are allowed.
1554ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
156fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   If the sector is not in use, all three pointers are NULL and
157fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tt_n_inuse is zero.
158fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
159fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjtypedef
160fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   struct {
161fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* The TCEntry area.  Size of this depends on the average
162fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         translation size.  We try and size it so it becomes full
163fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         precisely when this sector's translation table (tt) reaches
164fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         its load limit (SECTOR_TT_LIMIT_PERCENT). */
165fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      ULong* tc;
1664ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
167fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* The TTEntry array.  This is a fixed size, always containing
168fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         exactly N_TTES_PER_SECTOR entries. */
169fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      TTEntry* tt;
1706c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
171fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* This points to the current allocation point in tc. */
172fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      ULong* tc_next;
173de4a1d01951937632098a6cda45859afa587a06fsewardj
174fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* The count of tt entries with state InUse. */
175fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      Int tt_n_inuse;
1766c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
1776c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* Expandable arrays of tt indices for each of the ECLASS_N
1786c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         address range equivalence classes.  These hold indices into
1796c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         the containing sector's tt array, which in turn should point
1806c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         back here. */
1816c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      Int     ec2tte_size[ECLASS_N];
1826c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      Int     ec2tte_used[ECLASS_N];
1836c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      UShort* ec2tte[ECLASS_N];
184fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   }
185fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Sector;
186de4a1d01951937632098a6cda45859afa587a06fsewardj
187de4a1d01951937632098a6cda45859afa587a06fsewardj
1886c3769f487145a08c01b58d6e5db3ba274062ad4sewardj/*------------------ DECLS ------------------*/
1896c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
190fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* The root data structure is an array of sectors.  The index of the
191fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   youngest sector is recorded, and new translations are put into that
192fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sector.  When it fills up, we move along to the next sector and
193fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   start to fill that up, wrapping around at the end of the array.
194fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   That way, once all N_TC_SECTORS have been bought into use for the
195fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   first time, and are full, we then re-use the oldest sector,
196fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   endlessly.
197fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
198fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   When running, youngest sector should be between >= 0 and <
199fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   N_TC_SECTORS.  The initial -1 value indicates the TT/TC system is
200fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   not yet initialised.
201fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
202fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Sector sectors[N_SECTORS];
203fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Int    youngest_sector = -1;
2046c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
205fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* The number of ULongs in each TCEntry area.  This is computed once
206fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   at startup and does not change. */
207fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Int    tc_sector_szQ;
2086c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
2096c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
2105d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj/* A list of sector numbers, in the order which they should be
2115d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   searched to find translations.  This is an optimisation to be used
2125d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   when searching for translations and should not affect
2135d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   correctness.  -1 denotes "no entry". */
2145d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardjstatic Int sector_search_order[N_SECTORS];
2155d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
2165d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
2175f76de086a6d643db51e50a4e623df7dfc9b6161sewardj/* Fast helper for the TC.  A direct-mapped cache which holds a set of
2185f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   recently used (guest address, host address) pairs.  This array is
2195f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   referred to directly from m_dispatch/dispatch-<platform>.S.
2206c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
2215f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   Entries in tt_fast may refer to any valid TC entry, regardless of
222fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   which sector it's in.  Consequently we must be very careful to
223fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   invalidate this cache when TC entries are changed or disappear.
224c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
2255f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   A special .guest address - TRANSTAB_BOGUS_GUEST_ADDR -- must be
2265f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   pointed at to cause that cache entry to miss.  This relies on the
2275f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   assumption that no guest code actually has that address, hence a
2285f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   value 0x1 seems good.  m_translate gives the client a synthetic
2295f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   segfault if it tries to execute at this address.
2305f76de086a6d643db51e50a4e623df7dfc9b6161sewardj*/
2315f76de086a6d643db51e50a4e623df7dfc9b6161sewardj/*
2325f76de086a6d643db51e50a4e623df7dfc9b6161sewardjtypedef
2335f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   struct {
2345f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      Addr guest;
2355f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      Addr host;
2365f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   }
2375f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   FastCacheEntry;
2385f76de086a6d643db51e50a4e623df7dfc9b6161sewardj*/
2395f76de086a6d643db51e50a4e623df7dfc9b6161sewardj/*global*/ __attribute__((aligned(16)))
2405f76de086a6d643db51e50a4e623df7dfc9b6161sewardj           FastCacheEntry VG_(tt_fast)[VG_TT_FAST_SIZE];
2415f76de086a6d643db51e50a4e623df7dfc9b6161sewardj/*
2425f76de086a6d643db51e50a4e623df7dfc9b6161sewardj#define TRANSTAB_BOGUS_GUEST_ADDR ((Addr)1)
243fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
24492e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote
245fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* For profiling, we have a parallel array of pointers to .count
246fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   fields in TT entries.  Again, these pointers must be invalidated
247fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   when translations disappear.  A NULL pointer suffices to indicate
248fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   an unused slot.
2496c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
2505f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   When not profiling (the normal case, VG_(clo_profile_flags) == 0),
2515f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   all tt_fastN entries are set to NULL at startup and never read nor
2525f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   written after that.
2535f76de086a6d643db51e50a4e623df7dfc9b6161sewardj
2545f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   When profiling (VG_(clo_profile_flags) > 0), tt_fast and tt_fastN
2555f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   change together: if tt_fast[i].guest is TRANSTAB_BOGUS_GUEST_ADDR
2565f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   then the corresponding tt_fastN[i] must be null.  If
2575f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   tt_fast[i].guest is any other value, then tt_fastN[i] *must* point
2585f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   to the .count field of the corresponding TT entry.
2596c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
260fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tt_fast and tt_fastN are referred to from assembly code
261fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   (dispatch.S).
262fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
263fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*global*/ UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE];
264de4a1d01951937632098a6cda45859afa587a06fsewardj
265de4a1d01951937632098a6cda45859afa587a06fsewardj
266663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj/* Make sure we're not used before initialisation. */
267663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardjstatic Bool init_done = False;
268663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
269663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
270fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------ STATS DECLS ------------------*/
271de4a1d01951937632098a6cda45859afa587a06fsewardj
272fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of fast-cache updates and flushes done. */
273fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_fast_flushes = 0;
274fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_fast_updates = 0;
27522854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
276fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number of full lookups done. */
277fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_full_lookups = 0;
278fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_lookup_probes = 0;
27922854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
28026412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj/* Number/osize/tsize of translations entered; also the number of
28126412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj   those for which self-checking was requested. */
28226412bd2c4ef3e55683141f132ebd1eb32d8530bsewardjULong n_in_count    = 0;
28326412bd2c4ef3e55683141f132ebd1eb32d8530bsewardjULong n_in_osize    = 0;
28426412bd2c4ef3e55683141f132ebd1eb32d8530bsewardjULong n_in_tsize    = 0;
28526412bd2c4ef3e55683141f132ebd1eb32d8530bsewardjULong n_in_sc_count = 0;
286de4a1d01951937632098a6cda45859afa587a06fsewardj
287fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number/osize of translations discarded due to lack of space. */
288fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_dump_count = 0;
289fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_dump_osize = 0;
290fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
291fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Number/osize of translations discarded due to requests to do so. */
292fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_disc_count = 0;
293fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjULong n_disc_osize = 0;
294fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
295fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
2966c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/*-------------------------------------------------------------*/
2976c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/*--- Address-range equivalence class stuff                 ---*/
2986c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/*-------------------------------------------------------------*/
2996c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3006c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Return equivalence class number for a range. */
3016c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3026c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic Int range_to_eclass ( Addr64 start, UInt len )
3036c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
3046c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UInt mask   = (1 << ECLASS_WIDTH) - 1;
3056c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UInt lo     = (UInt)start;
3066c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UInt hi     = lo + len - 1;
3076c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UInt loBits = (lo >> ECLASS_SHIFT) & mask;
3086c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UInt hiBits = (hi >> ECLASS_SHIFT) & mask;
3096c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (loBits == hiBits) {
3106c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(loBits < ECLASS_N-1);
3116c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      return loBits;
3126c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   } else {
3136c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      return ECLASS_MISC;
3146c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
3156c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
3166c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3176c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3186c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Calculates the equivalence class numbers for any VexGuestExtent.
3196c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   These are written in *eclasses, which must be big enough to hold 3
3206c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Ints.  The number written, between 1 and 3, is returned.  The
3216c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   eclasses are presented in order, and any duplicates are removed.
3226c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj*/
3236c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3246c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic
3256c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjInt vexGuestExtents_to_eclasses ( /*OUT*/Int* eclasses,
3266c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                                  VexGuestExtents* vge )
3276c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
3286c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#  define SWAP(_lv1,_lv2) \
3296c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      do { Int t = _lv1; _lv1 = _lv2; _lv2 = t; } while (0)
3306c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3316c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int i, j, n_ec, r;
3326c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3336c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
3346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3356c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   n_ec = 0;
3366c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (i = 0; i < vge->n_used; i++) {
3376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      r = range_to_eclass( vge->base[i], (UInt)vge->len[i] );
3386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (r == ECLASS_MISC)
3396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         goto bad;
3406c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* only add if we haven't already seen it */
3416c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (j = 0; j < n_ec; j++)
3426c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (eclasses[j] == r)
3436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            break;
3446c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (j == n_ec)
3456c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         eclasses[n_ec++] = r;
3466c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
3476c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3486c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (n_ec == 1)
3496c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      return 1;
3506c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3516c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (n_ec == 2) {
3526c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* sort */
3536c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (eclasses[0] > eclasses[1])
3546c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         SWAP(eclasses[0], eclasses[1]);
3556c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      return 2;
3566c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
3576c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3586c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (n_ec == 3) {
3596c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* sort */
3606c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (eclasses[0] > eclasses[2])
3616c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         SWAP(eclasses[0], eclasses[2]);
3626c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (eclasses[0] > eclasses[1])
3636c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         SWAP(eclasses[0], eclasses[1]);
3646c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (eclasses[1] > eclasses[2])
3656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         SWAP(eclasses[1], eclasses[2]);
3666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      return 3;
3676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
3686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* NOTREACHED */
3706c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(0);
3716c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3726c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj  bad:
3736c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   eclasses[0] = ECLASS_MISC;
3746c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return 1;
3756c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3766c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#  undef SWAP
3776c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
3786c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3796c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3806c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Add tteno to the set of entries listed for equivalence class ec in
3816c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   this sector.  Returns used location in eclass array. */
3826c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3836c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic
3846c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjUInt addEClassNo ( /*MOD*/Sector* sec, Int ec, UShort tteno )
3856c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
3866c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int    old_sz, new_sz, i, r;
3876c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UShort *old_ar, *new_ar;
3886c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3896c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(ec >= 0 && ec < ECLASS_N);
3906c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(tteno < N_TTES_PER_SECTOR);
3916c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3926c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (0) VG_(printf)("ec %d  gets %d\n", ec, (Int)tteno);
3936c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3946c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (sec->ec2tte_used[ec] >= sec->ec2tte_size[ec]) {
3956c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3966c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sec->ec2tte_used[ec] == sec->ec2tte_size[ec]);
3976c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
3986c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      old_sz = sec->ec2tte_size[ec];
3996c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      old_ar = sec->ec2tte[ec];
4006c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      new_sz = old_sz==0 ? 8 : old_sz<64 ? 2*old_sz : (3*old_sz)/2;
4019c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj      new_ar = VG_(arena_malloc)(VG_AR_TTAUX, "transtab.aECN.1",
4029c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj                                 new_sz * sizeof(UShort));
4036c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (i = 0; i < old_sz; i++)
4046c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         new_ar[i] = old_ar[i];
4056c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (old_ar)
4066c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         VG_(arena_free)(VG_AR_TTAUX, old_ar);
4076c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      sec->ec2tte_size[ec] = new_sz;
4086c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      sec->ec2tte[ec] = new_ar;
4096c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4106c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (0) VG_(printf)("expand ec %d to %d\n", ec, new_sz);
4116c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
4126c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4136c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Common case */
4146c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   r = sec->ec2tte_used[ec]++;
4156c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(r >= 0 && r < sec->ec2tte_size[ec]);
4166c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   sec->ec2tte[ec][r] = tteno;
4176c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return (UInt)r;
4186c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
4196c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4206c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4216c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* 'vge' is being added to 'sec' at TT entry 'tteno'.  Add appropriate
4226c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   eclass entries to 'sec'. */
4236c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4246c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic
4256c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjvoid upd_eclasses_after_add ( /*MOD*/Sector* sec, Int tteno )
4266c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
4276c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int i, r, eclasses[3];
4286c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   TTEntry* tte;
4296c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(tteno >= 0 && tteno < N_TTES_PER_SECTOR);
4306c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4316c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   tte = &sec->tt[tteno];
4326c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   r = vexGuestExtents_to_eclasses( eclasses, &tte->vge );
4336c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(r >= 1 && r <= 3);
4356c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   tte->n_tte2ec = r;
4366c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (i = 0; i < r; i++) {
4386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      tte->tte2ec_ec[i] = eclasses[i];
4396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      tte->tte2ec_ix[i] = addEClassNo( sec, eclasses[i], (UShort)tteno );
4406c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
4416c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
4426c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4446c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Check the eclass info in 'sec' to ensure it is consistent.  Returns
4456c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   True if OK, False if something's not right.  Expensive. */
4466c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4476c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic Bool sanity_check_eclasses_in_sector ( Sector* sec )
4486c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
4496c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#  define BAD(_str) do { whassup = (_str); goto bad; } while (0)
4506c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4516c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   HChar*   whassup = NULL;
4526c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int      i, j, k, n, ec_num, ec_idx;
4536c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   TTEntry* tte;
4546c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UShort   tteno;
4556c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   ULong*   tce;
4566c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4576c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Basic checks on this sector */
4586c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (sec->tt_n_inuse < 0 || sec->tt_n_inuse > N_TTES_PER_SECTOR_USABLE)
4596c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      BAD("invalid sec->tt_n_inuse");
4606c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   tce = sec->tc_next;
4616c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (tce < &sec->tc[0] || tce > &sec->tc[tc_sector_szQ])
4626c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      BAD("sec->tc_next points outside tc");
4636c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4646c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* For each eclass ... */
4656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (i = 0; i < ECLASS_N; i++) {
4666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (sec->ec2tte_size[i] == 0 && sec->ec2tte[i] != NULL)
4676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         BAD("ec2tte_size/ec2tte mismatch(1)");
4686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (sec->ec2tte_size[i] != 0 && sec->ec2tte[i] == NULL)
4696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         BAD("ec2tte_size/ec2tte mismatch(2)");
4706c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (sec->ec2tte_used[i] < 0
4716c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj          || sec->ec2tte_used[i] > sec->ec2tte_size[i])
4726c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         BAD("implausible ec2tte_used");
4736c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (sec->ec2tte_used[i] == 0)
4746c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         continue;
4756c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4766c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* For each tt reference in each eclass .. ensure the reference
4776c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         is to a valid tt entry, and that the entry's address ranges
4786c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         really include this eclass. */
4796c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
4806c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (j = 0; j < sec->ec2tte_used[i]; j++) {
4816c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         tteno = sec->ec2tte[i][j];
4826c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (tteno == EC2TTE_DELETED)
4836c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            continue;
4846c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (tteno >= N_TTES_PER_SECTOR)
4856c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("implausible tteno");
4866c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         tte = &sec->tt[tteno];
4876c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (tte->status != InUse)
4886c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("tteno points to non-inuse tte");
4896c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (tte->n_tte2ec < 1 || tte->n_tte2ec > 3)
4906c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("tte->n_tte2ec out of range");
4916c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         /* Exactly least one of tte->eclasses[0 .. tte->n_eclasses-1]
4926c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            must equal i.  Inspect tte's eclass info. */
4936c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         n = 0;
4946c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         for (k = 0; k < tte->n_tte2ec; k++) {
4956c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            if (k < tte->n_tte2ec-1
4966c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                && tte->tte2ec_ec[k] >= tte->tte2ec_ec[k+1])
4976c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj               BAD("tte->tte2ec_ec[..] out of order");
4986c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            ec_num = tte->tte2ec_ec[k];
4996c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            if (ec_num < 0 || ec_num >= ECLASS_N)
5006c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj               BAD("tte->tte2ec_ec[..] out of range");
5016c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            if (ec_num != i)
5026c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj               continue;
5036c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            ec_idx = tte->tte2ec_ix[k];
5046c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            if (ec_idx < 0 || ec_idx >= sec->ec2tte_used[i])
5056c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj               BAD("tte->tte2ec_ix[..] out of range");
5066c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            if (ec_idx == j)
5076c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj               n++;
5086c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         }
5096c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (n != 1)
5106c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("tteno does not point back at eclass");
5116c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
5126c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
5136c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5146c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* That establishes that for each forward pointer from TTEntrys
5156c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      there is a corresponding backward pointer from the eclass[]
5166c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      arrays.  However, it doesn't rule out the possibility of other,
5176c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      bogus pointers in the eclass[] arrays.  So do those similarly:
5186c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      scan through them and check the TTEntryies they point at point
5196c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      back. */
5206c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5216c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (i = 0; i < N_TTES_PER_SECTOR_USABLE; i++) {
5226c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5236c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      tte = &sec->tt[i];
5246c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (tte->status == Empty || tte->status == Deleted) {
5256c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (tte->n_tte2ec != 0)
5266c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("tte->n_eclasses nonzero for unused tte");
5276c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         continue;
5286c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
5296c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5306c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(tte->status == InUse);
5316c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5326c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (tte->n_tte2ec < 1 || tte->n_tte2ec > 3)
5336c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         BAD("tte->n_eclasses out of range(2)");
5346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5356c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (j = 0; j < tte->n_tte2ec; j++) {
5366c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         ec_num = tte->tte2ec_ec[j];
5376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (ec_num < 0 || ec_num >= ECLASS_N)
5386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("tte->eclass[..] out of range");
5396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         ec_idx = tte->tte2ec_ix[j];
5406c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (ec_idx < 0 || ec_idx >= sec->ec2tte_used[ec_num])
5416c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("tte->ec_idx[..] out of range(2)");
5426c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (sec->ec2tte[ec_num][ec_idx] != i)
5436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            BAD("ec2tte does not point back to tte");
5446c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
5456c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
5466c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5476c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return True;
5486c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5496c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj  bad:
5506c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (whassup)
5516c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      VG_(debugLog)(0, "transtab", "eclass sanity fail: %s\n", whassup);
5526c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5536c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#  if 0
5546c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   VG_(printf)("eclass = %d\n", i);
5556c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   VG_(printf)("tteno = %d\n", (Int)tteno);
5566c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   switch (tte->status) {
5576c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      case InUse:   VG_(printf)("InUse\n"); break;
5586c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      case Deleted: VG_(printf)("Deleted\n"); break;
5596c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      case Empty:   VG_(printf)("Empty\n"); break;
5606c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
5616c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (tte->status != Empty) {
5626c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (k = 0; k < tte->vge.n_used; k++)
5636c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         VG_(printf)("0x%llx %d\n", tte->vge.base[k],
5646c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                                    (Int)tte->vge.len[k]);
5656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
5666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#  endif
5676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return False;
5696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5706c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj#  undef BAD
5716c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
5726c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5736c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5746c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Sanity check absolutely everything.  True == check passed. */
5756c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
5765f76de086a6d643db51e50a4e623df7dfc9b6161sewardj/* forwards */
5770ec07f32bbbb209d749b9974408e6f025ad40b31sewardjstatic Bool sanity_check_redir_tt_tc ( void );
5785f76de086a6d643db51e50a4e623df7dfc9b6161sewardjstatic Bool sanity_check_fastcache ( void );
5790ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
5805d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardjstatic Bool sanity_check_sector_search_order ( void )
5815d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj{
5825d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   Int i, j, nListed;
5835d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   /* assert the array is the right size */
5845d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   vg_assert(N_SECTORS == (sizeof(sector_search_order)
5855d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj                           / sizeof(sector_search_order[0])));
5865d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   /* Check it's of the form  valid_sector_numbers ++ [-1, -1, ..] */
5875d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   for (i = 0; i < N_SECTORS; i++) {
5885d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      if (sector_search_order[i] < 0 || sector_search_order[i] >= N_SECTORS)
5895d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         break;
5905d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   }
5915d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   nListed = i;
5925d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   for (/* */; i < N_SECTORS; i++) {
5935d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      if (sector_search_order[i] != -1)
5945d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         break;
5955d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   }
5965d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   if (i != N_SECTORS)
5975d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      return False;
5985d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   /* Check each sector number only appears once */
5995d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   for (i = 0; i < N_SECTORS; i++) {
6005d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      if (sector_search_order[i] == -1)
6015d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         continue;
6025d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      for (j = i+1; j < N_SECTORS; j++) {
6035d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         if (sector_search_order[j] == sector_search_order[i])
6045d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj            return False;
6055d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      }
6065d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   }
6075d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   /* Check that the number of listed sectors equals the number
6085d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      in use, by counting nListed back down. */
6095d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   for (i = 0; i < N_SECTORS; i++) {
6105d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      if (sectors[i].tc != NULL)
6115d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         nListed--;
6125d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   }
6135d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   if (nListed != 0)
6145d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      return False;
6155d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   return True;
6165d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj}
6175d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
6186c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic Bool sanity_check_all_sectors ( void )
6196c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
6206c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int     sno;
6216c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Bool    sane;
6226c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Sector* sec;
6236c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (sno = 0; sno < N_SECTORS; sno++) {
6246c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      sec = &sectors[sno];
6256c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (sec->tc == NULL)
6266c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         continue;
6276c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      sane = sanity_check_eclasses_in_sector( sec );
6286c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (!sane)
6296c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         return False;
6306c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
6315f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if ( !sanity_check_redir_tt_tc() )
6325f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      return False;
6335f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if ( !sanity_check_fastcache() )
6340ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      return False;
6355d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   if ( !sanity_check_sector_search_order() )
6365d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      return False;
6376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return True;
6386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
6396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
640fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
6415d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
642fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*-------------------------------------------------------------*/
6436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/*--- Add/find translations                                 ---*/
644fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*-------------------------------------------------------------*/
645fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
646fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic UInt vge_osize ( VexGuestExtents* vge )
647c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj{
648fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt i, n = 0;
649fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < vge->n_used; i++)
650fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      n += (UInt)vge->len[i];
651fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return n;
652c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj}
653c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
654fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic Bool isValidSector ( Int sector )
6556c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
656fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (sector < 0 || sector >= N_SECTORS)
657fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
658fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return True;
6596c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
660de4a1d01951937632098a6cda45859afa587a06fsewardj
661fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic inline UInt HASH_TT ( Addr64 key )
662de4a1d01951937632098a6cda45859afa587a06fsewardj{
663fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt kHi = (UInt)(key >> 32);
664fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt kLo = (UInt)key;
6656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UInt k32 = kHi ^ kLo;
6666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UInt ror = 7;
6676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (ror > 0)
6686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      k32 = (k32 >> ror) | (k32 << (32-ror));
6696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return k32 % N_TTES_PER_SECTOR;
670de4a1d01951937632098a6cda45859afa587a06fsewardj}
671de4a1d01951937632098a6cda45859afa587a06fsewardj
6725f76de086a6d643db51e50a4e623df7dfc9b6161sewardjstatic void setFastCacheEntry ( Addr64 key, ULong* tcptr, UInt* count )
673de4a1d01951937632098a6cda45859afa587a06fsewardj{
6743387dda4479102751d544c176a7bfc24f3766669sewardj   UInt cno = (UInt)VG_TT_FAST_HASH(key);
6755f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   VG_(tt_fast)[cno].guest = (Addr)key;
6765f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   VG_(tt_fast)[cno].host  = (Addr)tcptr;
6775f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if (VG_(clo_profile_flags) > 0)
6785f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      VG_(tt_fastN)[cno] = count;
679fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_fast_updates++;
6805f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   /* This shouldn't fail.  It should be assured by m_translate
6815f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      which should reject any attempt to make translation of code
6825f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      starting at TRANSTAB_BOGUS_GUEST_ADDR. */
6835f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(VG_(tt_fast)[cno].guest != TRANSTAB_BOGUS_GUEST_ADDR);
6846c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
685de4a1d01951937632098a6cda45859afa587a06fsewardj
6865f76de086a6d643db51e50a4e623df7dfc9b6161sewardj/* Invalidate the fast cache's counter array, VG_(tt_fastN). */
6875f76de086a6d643db51e50a4e623df7dfc9b6161sewardjstatic void invalidateFastNCache ( void )
6886c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
689fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UInt j;
69065e193939481231a8f6699201258e0a2828357e8sewardj   vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
69165e193939481231a8f6699201258e0a2828357e8sewardj   for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
69265e193939481231a8f6699201258e0a2828357e8sewardj      VG_(tt_fastN)[j+0] = NULL;
69365e193939481231a8f6699201258e0a2828357e8sewardj      VG_(tt_fastN)[j+1] = NULL;
69465e193939481231a8f6699201258e0a2828357e8sewardj      VG_(tt_fastN)[j+2] = NULL;
69565e193939481231a8f6699201258e0a2828357e8sewardj      VG_(tt_fastN)[j+3] = NULL;
6966c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
69765e193939481231a8f6699201258e0a2828357e8sewardj   vg_assert(j == VG_TT_FAST_SIZE);
6985f76de086a6d643db51e50a4e623df7dfc9b6161sewardj}
6995f76de086a6d643db51e50a4e623df7dfc9b6161sewardj
7005f76de086a6d643db51e50a4e623df7dfc9b6161sewardj/* Invalidate the fast cache VG_(tt_fast).  If profiling, also
7015f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   invalidate the fast cache's counter array VG_(tt_fastN), otherwise
7025f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   don't touch it. */
7035f76de086a6d643db51e50a4e623df7dfc9b6161sewardjstatic void invalidateFastCache ( void )
7045f76de086a6d643db51e50a4e623df7dfc9b6161sewardj{
7055f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   UInt j;
7065f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   /* This loop is popular enough to make it worth unrolling a
7075f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      bit, at least on ppc32. */
7085f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(VG_TT_FAST_SIZE > 0 && (VG_TT_FAST_SIZE % 4) == 0);
7095f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   for (j = 0; j < VG_TT_FAST_SIZE; j += 4) {
7105f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      VG_(tt_fast)[j+0].guest = TRANSTAB_BOGUS_GUEST_ADDR;
7115f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      VG_(tt_fast)[j+1].guest = TRANSTAB_BOGUS_GUEST_ADDR;
7125f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      VG_(tt_fast)[j+2].guest = TRANSTAB_BOGUS_GUEST_ADDR;
7135f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      VG_(tt_fast)[j+3].guest = TRANSTAB_BOGUS_GUEST_ADDR;
7145f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   }
7155f76de086a6d643db51e50a4e623df7dfc9b6161sewardj
7165f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if (VG_(clo_profile_flags) > 0)
7175f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      invalidateFastNCache();
7185f76de086a6d643db51e50a4e623df7dfc9b6161sewardj
7195f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(j == VG_TT_FAST_SIZE);
720fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_fast_flushes++;
7216c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
722de4a1d01951937632098a6cda45859afa587a06fsewardj
7235f76de086a6d643db51e50a4e623df7dfc9b6161sewardjstatic Bool sanity_check_fastcache ( void )
7245f76de086a6d643db51e50a4e623df7dfc9b6161sewardj{
7255f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   UInt j;
7265f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if (0) VG_(printf)("sanity check fastcache\n");
7275f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if (VG_(clo_profile_flags) > 0) {
7285f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      /* profiling */
7295f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      for (j = 0; j < VG_TT_FAST_SIZE; j++) {
7305f76de086a6d643db51e50a4e623df7dfc9b6161sewardj         if (VG_(tt_fastN)[j] == NULL
7315f76de086a6d643db51e50a4e623df7dfc9b6161sewardj             && VG_(tt_fast)[j].guest != TRANSTAB_BOGUS_GUEST_ADDR)
7325f76de086a6d643db51e50a4e623df7dfc9b6161sewardj            return False;
7335f76de086a6d643db51e50a4e623df7dfc9b6161sewardj         if (VG_(tt_fastN)[j] != NULL
7345f76de086a6d643db51e50a4e623df7dfc9b6161sewardj             && VG_(tt_fast)[j].guest == TRANSTAB_BOGUS_GUEST_ADDR)
7355f76de086a6d643db51e50a4e623df7dfc9b6161sewardj            return False;
7365f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      }
7375f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   } else {
7385f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      /* not profiling */
7395f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      for (j = 0; j < VG_TT_FAST_SIZE; j++) {
7405f76de086a6d643db51e50a4e623df7dfc9b6161sewardj         if (VG_(tt_fastN)[j] != NULL)
7415f76de086a6d643db51e50a4e623df7dfc9b6161sewardj            return False;
7425f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      }
7435f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   }
7445f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   return True;
7455f76de086a6d643db51e50a4e623df7dfc9b6161sewardj}
7465f76de086a6d643db51e50a4e623df7dfc9b6161sewardj
747fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic void initialiseSector ( Int sno )
7486c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
74945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Int    i;
75045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   SysRes sres;
7516c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Sector* sec;
752fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(isValidSector(sno));
753fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
7545d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   { Bool sane = sanity_check_sector_search_order();
7555d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj     vg_assert(sane);
7565d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   }
7576c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   sec = &sectors[sno];
7586c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
7596c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (sec->tc == NULL) {
7606c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
761fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* Sector has never been used before.  Need to allocate tt and
762fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         tc. */
7636c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sec->tt == NULL);
7646c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sec->tc_next == NULL);
7656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sec->tt_n_inuse == 0);
7666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (i = 0; i < ECLASS_N; i++) {
7676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         vg_assert(sec->ec2tte_size[i] == 0);
7686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         vg_assert(sec->ec2tte_used[i] == 0);
7696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         vg_assert(sec->ec2tte[i] == NULL);
7706c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
77145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
77245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(debugLog)(1,"transtab", "allocate sector %d\n", sno);
77345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
77445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      sres = VG_(am_mmap_anon_float_valgrind)( 8 * tc_sector_szQ );
775cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      if (sr_isError(sres)) {
77645f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(out_of_memory_NORETURN)("initialiseSector(TC)",
77745f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                     8 * tc_sector_szQ );
77845f4e7c91119c7d01a59f5e827c67841632c9314sewardj	 /*NOTREACHED*/
77945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
780cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      sec->tc = (ULong*)(AddrH)sr_Res(sres);
78145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
78245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      sres = VG_(am_mmap_anon_float_valgrind)
78345f4e7c91119c7d01a59f5e827c67841632c9314sewardj                ( N_TTES_PER_SECTOR * sizeof(TTEntry) );
784cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      if (sr_isError(sres)) {
78545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         VG_(out_of_memory_NORETURN)("initialiseSector(TT)",
78645f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                     N_TTES_PER_SECTOR * sizeof(TTEntry) );
78745f4e7c91119c7d01a59f5e827c67841632c9314sewardj	 /*NOTREACHED*/
78845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      }
789cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      sec->tt = (TTEntry*)(AddrH)sr_Res(sres);
7906c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
7916c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (i = 0; i < N_TTES_PER_SECTOR; i++) {
7926c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sec->tt[i].status   = Empty;
7936c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sec->tt[i].n_tte2ec = 0;
7946c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
79545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
7965d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      /* Add an entry in the sector_search_order */
7975d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      for (i = 0; i < N_SECTORS; i++) {
7985d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         if (sector_search_order[i] == -1)
7995d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj            break;
8005d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      }
8015d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      vg_assert(i >= 0 && i < N_SECTORS);
8025d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      sector_search_order[i] = sno;
8035d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
804fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (VG_(clo_verbosity) > 2)
805738856f99eea33d86ce91dcb1d6cd5b151e307casewardj         VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d\n", sno);
8066c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
807fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   } else {
8086c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
8096c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* Sector has been used before.  Dump the old contents. */
81045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(debugLog)(1,"transtab", "recycle sector %d\n", sno);
8116c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sec->tt != NULL);
8126c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sec->tc_next != NULL);
8136c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      n_dump_count += sec->tt_n_inuse;
8146c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
8156c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* Visit each just-about-to-be-abandoned translation. */
816fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      for (i = 0; i < N_TTES_PER_SECTOR; i++) {
8176c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (sec->tt[i].status == InUse) {
8186c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            vg_assert(sec->tt[i].n_tte2ec >= 1);
8196c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            vg_assert(sec->tt[i].n_tte2ec <= 3);
8206c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            n_dump_osize += vge_osize(&sec->tt[i].vge);
8213786772222c5b31fd6cc5586bcd1ce0da58f1dbesewardj            /* Tell the tool too. */
8220b9d74abd0a663b530d290b2b788ddeda46e5400sewardj            if (VG_(needs).superblock_discards) {
8230b9d74abd0a663b530d290b2b788ddeda46e5400sewardj               VG_TDICT_CALL( tool_discard_superblock_info,
8244ba057cce1d81a949f5a899b5abb99e90a731bccsewardj                              sec->tt[i].entry,
8256c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                              sec->tt[i].vge );
8263786772222c5b31fd6cc5586bcd1ce0da58f1dbesewardj            }
8276c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         } else {
8286c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            vg_assert(sec->tt[i].n_tte2ec == 0);
8296c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         }
8306c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sec->tt[i].status   = Empty;
8316c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sec->tt[i].n_tte2ec = 0;
8326c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
8336c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
8346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* Free up the eclass structures. */
8356c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (i = 0; i < ECLASS_N; i++) {
8366c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (sec->ec2tte_size[i] == 0) {
8376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            vg_assert(sec->ec2tte_used[i] == 0);
8386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            vg_assert(sec->ec2tte[i] == NULL);
8396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         } else {
8406c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            vg_assert(sec->ec2tte[i] != NULL);
8416c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            VG_(arena_free)(VG_AR_TTAUX, sec->ec2tte[i]);
8426c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            sec->ec2tte[i] = NULL;
8436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            sec->ec2tte_size[i] = 0;
8446c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            sec->ec2tte_used[i] = 0;
845fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
846fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      }
8476c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
8485d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      /* Sanity check: ensure it is already in
8495d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         sector_search_order[]. */
8505d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      for (i = 0; i < N_SECTORS; i++) {
8515d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         if (sector_search_order[i] == sno)
8525d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj            break;
8535d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      }
8545d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      vg_assert(i >= 0 && i < N_SECTORS);
8555d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
856fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (VG_(clo_verbosity) > 2)
857738856f99eea33d86ce91dcb1d6cd5b151e307casewardj         VG_(message)(Vg_DebugMsg, "TT/TC: recycle sector %d\n", sno);
8586c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
8594ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
8606c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   sec->tc_next = sec->tc;
8616c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   sec->tt_n_inuse = 0;
862fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
863fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   invalidateFastCache();
8645d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
8655d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   { Bool sane = sanity_check_sector_search_order();
8665d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj     vg_assert(sane);
8675d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   }
8686c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
869de4a1d01951937632098a6cda45859afa587a06fsewardj
87010f08cf5b84882eebbb6712a7be890577650e8adsewardjstatic void invalidate_icache ( void *ptr, Int nbytes )
87185665ca6fa29dd64754dabe50eb98f25896e752acerion{
8722c48c7b0a453d32375a4df17e153011b797ef28csewardj#  if defined(VGA_ppc32) || defined(VGA_ppc64)
87310f08cf5b84882eebbb6712a7be890577650e8adsewardj   Addr startaddr = (Addr) ptr;
87410f08cf5b84882eebbb6712a7be890577650e8adsewardj   Addr endaddr   = startaddr + nbytes;
875e3826cfe34ec9a0caa570a0d15647b28711584a0sewardj   Addr cls;
87610f08cf5b84882eebbb6712a7be890577650e8adsewardj   Addr addr;
877e3826cfe34ec9a0caa570a0d15647b28711584a0sewardj   VexArchInfo vai;
878e3826cfe34ec9a0caa570a0d15647b28711584a0sewardj
8795f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if (nbytes == 0) return;
8805f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(nbytes > 0);
8815f76de086a6d643db51e50a4e623df7dfc9b6161sewardj
882e3826cfe34ec9a0caa570a0d15647b28711584a0sewardj   VG_(machine_get_VexArchInfo)( NULL, &vai );
8831f0d814045aba94e01e62e04e968ca8b970b3d44cerion   cls = vai.ppc_cache_line_szB;
88410f08cf5b84882eebbb6712a7be890577650e8adsewardj
8852bf6ba55b04ea9a58098f041c5ee149539c0f081sewardj   /* Stay sane .. */
88689230cace4f5acad8037e4cb4b3e49e83d3a275bsewardj   vg_assert(cls == 32 || cls == 64 || cls == 128);
88785665ca6fa29dd64754dabe50eb98f25896e752acerion
88885665ca6fa29dd64754dabe50eb98f25896e752acerion   startaddr &= ~(cls - 1);
88959570ffbe31930ab4d678754daaeec0715117a3dsewardj   for (addr = startaddr; addr < endaddr; addr += cls) {
89059570ffbe31930ab4d678754daaeec0715117a3dsewardj      __asm__ __volatile__("dcbst 0,%0" : : "r" (addr));
89159570ffbe31930ab4d678754daaeec0715117a3dsewardj   }
89259570ffbe31930ab4d678754daaeec0715117a3dsewardj   __asm__ __volatile__("sync");
89359570ffbe31930ab4d678754daaeec0715117a3dsewardj   for (addr = startaddr; addr < endaddr; addr += cls) {
89459570ffbe31930ab4d678754daaeec0715117a3dsewardj      __asm__ __volatile__("icbi 0,%0" : : "r" (addr));
89559570ffbe31930ab4d678754daaeec0715117a3dsewardj   }
89659570ffbe31930ab4d678754daaeec0715117a3dsewardj   __asm__ __volatile__("sync; isync");
89710f08cf5b84882eebbb6712a7be890577650e8adsewardj
89810f08cf5b84882eebbb6712a7be890577650e8adsewardj#  elif defined(VGA_x86)
89910f08cf5b84882eebbb6712a7be890577650e8adsewardj   /* no need to do anything, hardware provides coherence */
90010f08cf5b84882eebbb6712a7be890577650e8adsewardj
90110f08cf5b84882eebbb6712a7be890577650e8adsewardj#  elif defined(VGA_amd64)
90210f08cf5b84882eebbb6712a7be890577650e8adsewardj   /* no need to do anything, hardware provides coherence */
90310f08cf5b84882eebbb6712a7be890577650e8adsewardj
90459570ffbe31930ab4d678754daaeec0715117a3dsewardj#  elif defined(VGP_arm_linux)
90559570ffbe31930ab4d678754daaeec0715117a3dsewardj   /* ARM cache flushes are privileged, so we must defer to the kernel. */
90659570ffbe31930ab4d678754daaeec0715117a3dsewardj   Addr startaddr = (Addr) ptr;
90759570ffbe31930ab4d678754daaeec0715117a3dsewardj   Addr endaddr   = startaddr + nbytes;
90859570ffbe31930ab4d678754daaeec0715117a3dsewardj   VG_(do_syscall2)(__NR_ARM_cacheflush, startaddr, endaddr);
90959570ffbe31930ab4d678754daaeec0715117a3dsewardj
91010f08cf5b84882eebbb6712a7be890577650e8adsewardj#  else
91110f08cf5b84882eebbb6712a7be890577650e8adsewardj#    error "Unknown ARCH"
91210f08cf5b84882eebbb6712a7be890577650e8adsewardj#  endif
91385665ca6fa29dd64754dabe50eb98f25896e752acerion}
91485665ca6fa29dd64754dabe50eb98f25896e752acerion
915de4a1d01951937632098a6cda45859afa587a06fsewardj
916fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Add a translation of vge to TT/TC.  The translation is temporarily
917fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   in code[0 .. code_len-1].
918de4a1d01951937632098a6cda45859afa587a06fsewardj
919fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   pre: youngest_sector points to a valid (although possibly full)
920fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sector.
921fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
9228bddf58af8cc7342d4bde6712c5a6a33bf2850d4njnvoid VG_(add_to_transtab)( VexGuestExtents* vge,
9238bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn                           Addr64           entry,
9248bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn                           AddrH            code,
92526412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj                           UInt             code_len,
92626412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj                           Bool             is_self_checking )
92722854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj{
928fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int    tcAvailQ, reqdQ, y, i;
9295f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   ULong  *tcptr, *tcptr2;
930fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UChar* srcP;
931fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   UChar* dstP;
932fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
933663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(init_done);
934fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
935e808930793aeddc4cfd3e7a94b665913bec2566csewardj
936e808930793aeddc4cfd3e7a94b665913bec2566csewardj   /* 60000: should agree with N_TMPBUF in m_translate.c. */
937e808930793aeddc4cfd3e7a94b665913bec2566csewardj   vg_assert(code_len > 0 && code_len < 60000);
938fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
939fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (0)
9408bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn      VG_(printf)("add_to_transtab(entry = 0x%llx, len = %d)\n",
941fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                  entry, code_len);
942fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
943fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_in_count++;
944fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_in_tsize += code_len;
945fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_in_osize += vge_osize(vge);
94626412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj   if (is_self_checking)
94726412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj      n_in_sc_count++;
948fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
949fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   y = youngest_sector;
950fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(isValidSector(y));
951fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
952fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (sectors[y].tc == NULL)
953fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      initialiseSector(y);
954fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
955fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Try putting the translation in this sector. */
9565f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   reqdQ = (code_len + 7) >> 3;
957fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
958fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Will it fit in tc? */
959fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
960fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj              - ((ULong*)(sectors[y].tc_next));
961fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ >= 0);
962fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ <= tc_sector_szQ);
963fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
964fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (tcAvailQ < reqdQ
965fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj       || sectors[y].tt_n_inuse >= N_TTES_PER_SECTOR_USABLE) {
966fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* No.  So move on to the next sector.  Either it's never been
967fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         used before, in which case it will get its tt/tc allocated
968fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         now, or it has been used before, in which case it is set to be
969fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         empty, hence throwing out the oldest sector. */
970a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj      vg_assert(tc_sector_szQ > 0);
971a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj      VG_(debugLog)(1,"transtab",
972a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj                      "declare sector %d full "
973a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj                      "(TT loading %2d%%, TC loading %2d%%)\n",
974a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj                      y,
975a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj                      (100 * sectors[y].tt_n_inuse)
976a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj                         / N_TTES_PER_SECTOR,
977a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj                      (100 * (tc_sector_szQ - tcAvailQ))
978a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj                         / tc_sector_szQ);
979fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      youngest_sector++;
980fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (youngest_sector >= N_SECTORS)
981fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         youngest_sector = 0;
982fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      y = youngest_sector;
983fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      initialiseSector(y);
984fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   }
98522854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
986fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Be sure ... */
987fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   tcAvailQ = ((ULong*)(&sectors[y].tc[tc_sector_szQ]))
988fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj              - ((ULong*)(sectors[y].tc_next));
989fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ >= 0);
990fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ <= tc_sector_szQ);
991fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tcAvailQ >= reqdQ);
992fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sectors[y].tt_n_inuse < N_TTES_PER_SECTOR_USABLE);
993fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sectors[y].tt_n_inuse >= 0);
994fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
995fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Copy into tc. */
9965f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   tcptr = sectors[y].tc_next;
9975f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(tcptr >= &sectors[y].tc[0]);
9985f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(tcptr <= &sectors[y].tc[tc_sector_szQ]);
999fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
10005f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   dstP = (UChar*)tcptr;
1001fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   srcP = (UChar*)code;
1002fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < code_len; i++)
1003fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      dstP[i] = srcP[i];
1004fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tc_next += reqdQ;
1005fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt_n_inuse++;
1006fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
100785665ca6fa29dd64754dabe50eb98f25896e752acerion   invalidate_icache( dstP, code_len );
100885665ca6fa29dd64754dabe50eb98f25896e752acerion
1009fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* more paranoia */
10105f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   tcptr2 = sectors[y].tc_next;
10115f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(tcptr2 >= &sectors[y].tc[0]);
10125f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(tcptr2 <= &sectors[y].tc[tc_sector_szQ]);
1013fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1014fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Find an empty tt slot, and use it.  There must be such a slot
1015fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      since tt is never allowed to get completely full. */
1016fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   i = HASH_TT(entry);
1017fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(i >= 0 && i < N_TTES_PER_SECTOR);
101822854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj   while (True) {
1019fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (sectors[y].tt[i].status == Empty
1020fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj          || sectors[y].tt[i].status == Deleted)
1021fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         break;
1022fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      i++;
1023fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (i >= N_TTES_PER_SECTOR)
1024fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         i = 0;
102522854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj   }
1026fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1027fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].status = InUse;
10285f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   sectors[y].tt[i].tcptr  = tcptr;
1029fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].count  = 0;
1030fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].weight = 1;
1031fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].vge    = *vge;
1032fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   sectors[y].tt[i].entry  = entry;
1033fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
10346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Update the fast-cache. */
10355f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   setFastCacheEntry( entry, tcptr, &sectors[y].tt[i].count );
10366c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
10376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Note the eclass numbers for this translation. */
10386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   upd_eclasses_after_add( &sectors[y], i );
103922854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj}
104022854b907c1925a9af97ad20ca3dacb5e300d6f9sewardj
1041fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1042fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/* Search for the translation of the given guest address.  If
1043fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   requested, a successful search can also cause the fast-caches to be
1044fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   updated.
1045fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj*/
1046fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjBool VG_(search_transtab) ( /*OUT*/AddrH* result,
1047fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                            Addr64        guest_addr,
1048fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                            Bool          upd_cache )
10496c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
1050fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int i, j, k, kstart, sno;
1051663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
1052663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(init_done);
1053fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Find the initial probe point just once.  It will be the same in
1054fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      all sectors and avoids multiple expensive % operations. */
1055fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   n_full_lookups++;
1056fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   k      = -1;
1057fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   kstart = HASH_TT(guest_addr);
1058fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(kstart >= 0 && kstart < N_TTES_PER_SECTOR);
1059fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
10605d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   /* Search in all the sectors,using sector_search_order[] as a
10615d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      heuristic guide as to what order to visit the sectors. */
1062fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < N_SECTORS; i++) {
1063fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
10645d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      sno = sector_search_order[i];
10655d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      if (UNLIKELY(sno == -1))
10665d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj         return False; /* run out of sectors to search */
1067fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1068fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      k = kstart;
1069fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      for (j = 0; j < N_TTES_PER_SECTOR; j++) {
1070fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         n_lookup_probes++;
1071fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[k].status == InUse
1072fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             && sectors[sno].tt[k].entry == guest_addr) {
1073fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            /* found it */
1074fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            if (upd_cache)
1075fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               setFastCacheEntry(
10765f76de086a6d643db51e50a4e623df7dfc9b6161sewardj                  guest_addr, sectors[sno].tt[k].tcptr,
1077fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                              &sectors[sno].tt[k].count );
1078fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            if (result)
10795f76de086a6d643db51e50a4e623df7dfc9b6161sewardj               *result = (AddrH)sectors[sno].tt[k].tcptr;
10805d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj            /* pull this one one step closer to the front.  For large
10815d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj               apps this more or less halves the number of required
10825d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj               probes. */
10835d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj            if (i > 0) {
10845d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj               Int tmp = sector_search_order[i-1];
10855d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj               sector_search_order[i-1] = sector_search_order[i];
10865d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj               sector_search_order[i] = tmp;
10875d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj            }
1088fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            return True;
1089fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
1090fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[k].status == Empty)
1091fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            break; /* not found in this sector */
1092fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         k++;
1093fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (k == N_TTES_PER_SECTOR)
1094fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            k = 0;
10956c3769f487145a08c01b58d6e5db3ba274062ad4sewardj      }
1096fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1097fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      /* If we fall off the end, all entries are InUse and not
1098fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         matching, or Deleted.  In any case we did not find it in this
1099fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         sector. */
11006c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
1101fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1102fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Not found in any sector. */
1103fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return False;
11046c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
1105de4a1d01951937632098a6cda45859afa587a06fsewardj
1106de4a1d01951937632098a6cda45859afa587a06fsewardj
11076c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/*-------------------------------------------------------------*/
11086c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/*--- Delete translations.                                  ---*/
11096c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/*-------------------------------------------------------------*/
11106c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11110ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/* forward */
11120ec07f32bbbb209d749b9974408e6f025ad40b31sewardjstatic void unredir_discard_translations( Addr64, ULong );
11130ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
11146c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Stuff for deleting translations which intersect with a given
11156c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   address range.  Unfortunately, to make this run at a reasonable
11166c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   speed, it is complex. */
1117fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1118fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic inline
1119a30545069556d3dca4ca3feb7c621bdcb7b34107sewardjBool overlap1 ( Addr64 s1, ULong r1, Addr64 s2, ULong r2 )
11206c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
1121a30545069556d3dca4ca3feb7c621bdcb7b34107sewardj   Addr64 e1 = s1 + r1 - 1ULL;
1122a30545069556d3dca4ca3feb7c621bdcb7b34107sewardj   Addr64 e2 = s2 + r2 - 1ULL;
1123fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (e1 < s2 || e2 < s1)
1124fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
1125fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return True;
11266c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
1127de4a1d01951937632098a6cda45859afa587a06fsewardj
1128fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic inline
1129a30545069556d3dca4ca3feb7c621bdcb7b34107sewardjBool overlaps ( Addr64 start, ULong range, VexGuestExtents* vge )
11306c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
1131fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (overlap1(start, range, vge->base[0], (UInt)vge->len[0]))
1132fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return True;
1133fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (vge->n_used < 2)
1134fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
1135fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (overlap1(start, range, vge->base[1], (UInt)vge->len[1]))
1136fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return True;
1137fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (vge->n_used < 3)
1138fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return False;
1139fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (overlap1(start, range, vge->base[2], (UInt)vge->len[2]))
1140fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      return True;
1141fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return False;
11426c3769f487145a08c01b58d6e5db3ba274062ad4sewardj}
1143de4a1d01951937632098a6cda45859afa587a06fsewardj
1144de4a1d01951937632098a6cda45859afa587a06fsewardj
11456c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Delete a tt entry, and update all the eclass data accordingly. */
11466c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11476c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic void delete_tte ( /*MOD*/Sector* sec, Int tteno )
11486c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
11496c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int      i, ec_num, ec_idx;
11506c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   TTEntry* tte;
11516c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11526c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(tteno >= 0 && tteno < N_TTES_PER_SECTOR);
11536c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   tte = &sec->tt[tteno];
11546c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(tte->status == InUse);
11556c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(tte->n_tte2ec >= 1 && tte->n_tte2ec <= 3);
11566c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11576c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Deal with the ec-to-tte links first. */
11586c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (i = 0; i < tte->n_tte2ec; i++) {
11596c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      ec_num = (Int)tte->tte2ec_ec[i];
11606c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      ec_idx = tte->tte2ec_ix[i];
11616c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(ec_num >= 0 && ec_num < ECLASS_N);
11626c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(ec_idx >= 0);
11636c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(ec_idx < sec->ec2tte_used[ec_num]);
11646c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* Assert that the two links point at each other. */
11656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sec->ec2tte[ec_num][ec_idx] == (UShort)tteno);
11666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* "delete" the pointer back to here. */
11676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      sec->ec2tte[ec_num][ec_idx] = EC2TTE_DELETED;
11686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
11696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11706c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Now fix up this TTEntry. */
11716c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   tte->status   = Deleted;
11726c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   tte->n_tte2ec = 0;
11736c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11746c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Stats .. */
11756c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   sec->tt_n_inuse--;
11766c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   n_disc_count++;
11776c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   n_disc_osize += vge_osize(&tte->vge);
11786c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11796c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Tell the tool too. */
11800b9d74abd0a663b530d290b2b788ddeda46e5400sewardj   if (VG_(needs).superblock_discards) {
11810b9d74abd0a663b530d290b2b788ddeda46e5400sewardj      VG_TDICT_CALL( tool_discard_superblock_info,
11824ba057cce1d81a949f5a899b5abb99e90a731bccsewardj                     tte->entry,
11836c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                     tte->vge );
11846c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
11856c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
11866c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11876c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11886c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Delete translations from sec which intersect specified range, but
11896c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   only consider translations in the specified eclass. */
11906c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
11916c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic
11926c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjBool delete_translations_in_sector_eclass ( /*MOD*/Sector* sec,
11936c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                                            Addr64 guest_start, ULong range,
11946c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                                            Int ec )
11956c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
11966c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int      i;
11976c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   UShort   tteno;
11986c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Bool     anyDeld = False;
11996c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   TTEntry* tte;
12006c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12016c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   vg_assert(ec >= 0 && ec < ECLASS_N);
12026c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12036c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (i = 0; i < sec->ec2tte_used[ec]; i++) {
12046c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12056c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      tteno = sec->ec2tte[ec][i];
12066c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (tteno == EC2TTE_DELETED) {
12076c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         /* already deleted */
12086c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         continue;
12096c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
12106c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12116c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(tteno < N_TTES_PER_SECTOR);
12126c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12136c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      tte = &sec->tt[tteno];
12146c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(tte->status == InUse);
12156c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12166c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (overlaps( guest_start, range, &tte->vge )) {
12176c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         anyDeld = True;
12186c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         delete_tte( sec, (Int)tteno );
12196c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
12206c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12216c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
12226c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12236c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return anyDeld;
12246c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
12256c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12266c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12276c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj/* Delete translations from sec which intersect specified range, the
12286c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   slow way, by inspecting all translations in sec. */
12296c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12306c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjstatic
12316c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardjBool delete_translations_in_sector ( /*MOD*/Sector* sec,
12326c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                                     Addr64 guest_start, ULong range )
12336c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj{
12346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int  i;
12356c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Bool anyDeld = False;
12366c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12376c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   for (i = 0; i < N_TTES_PER_SECTOR; i++) {
12386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      if (sec->tt[i].status == InUse
12396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj          && overlaps( guest_start, range, &sec->tt[i].vge )) {
12406c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         anyDeld = True;
12416c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         delete_tte( sec, i );
12426c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
12436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
12446c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12456c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   return anyDeld;
12466c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj}
12476c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12486c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
124945f4e7c91119c7d01a59f5e827c67841632c9314sewardjvoid VG_(discard_translations) ( Addr64 guest_start, ULong range,
125045f4e7c91119c7d01a59f5e827c67841632c9314sewardj                                 HChar* who )
12516c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
12526c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Sector* sec;
12536c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int     sno, ec;
12546c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Bool    anyDeleted = False;
12556c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
1256663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(init_done);
1257663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
1258a16ea0a5fa05dac343e63feddf63f51cb0c340bdsewardj   VG_(debugLog)(2, "transtab",
125945f4e7c91119c7d01a59f5e827c67841632c9314sewardj                    "discard_translations(0x%llx, %lld) req by %s\n",
126045f4e7c91119c7d01a59f5e827c67841632c9314sewardj                    guest_start, range, who );
126145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
12626c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Pre-deletion sanity check */
12636c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (VG_(clo_sanity_level >= 4)) {
12646c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      Bool sane = sanity_check_all_sectors();
12656c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sane);
12666c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
12676c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (range == 0)
12696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      return;
12706c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12716c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* There are two different ways to do this.
12726c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12736c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      If the range fits within a single address-range equivalence
12746c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      class, as will be the case for a cache line sized invalidation,
12756c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      then we only have to inspect the set of translations listed in
12766c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      that equivalence class, and also in the "sin-bin" equivalence
12776c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      class ECLASS_MISC.
12786c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12796c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      Otherwise, the invalidation is of a larger range and probably
12806c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      results from munmap.  In this case it's (probably!) faster just
12816c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      to inspect all translations, dump those we don't want, and
12826c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      regenerate the equivalence class information (since modifying it
12836c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      in-situ is even more expensive).
12846c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   */
12856c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12866c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* First off, figure out if the range falls within a single class,
12876c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      and if so which one. */
12886c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12896c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   ec = ECLASS_MISC;
12906c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (range < (1ULL << ECLASS_SHIFT))
12916c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      ec = range_to_eclass( guest_start, (UInt)range );
12926c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12936c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* if ec is ECLASS_MISC then we aren't looking at just a single
12946c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      class, so use the slow scheme.  Else use the fast scheme,
12956c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      examining 'ec' and ECLASS_MISC. */
12966c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12976c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (ec != ECLASS_MISC) {
12986c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
12996c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      VG_(debugLog)(2, "transtab",
13006c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                       "                    FAST, ec = %d\n", ec);
13016c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
13026c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* Fast scheme */
13036c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(ec >= 0 && ec < ECLASS_MISC);
13046c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
13056c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (sno = 0; sno < N_SECTORS; sno++) {
13066c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sec = &sectors[sno];
13076c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (sec->tc == NULL)
13086c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            continue;
13096c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         anyDeleted |= delete_translations_in_sector_eclass(
13106c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                         sec, guest_start, range, ec );
13116c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         anyDeleted |= delete_translations_in_sector_eclass(
13126c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                         sec, guest_start, range, ECLASS_MISC );
13136c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
13146c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
13156c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   } else {
13166c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
13176c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* slow scheme */
13186c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
13196c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      VG_(debugLog)(2, "transtab",
13206c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                       "                    SLOW, ec = %d\n", ec);
13216c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
13226c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (sno = 0; sno < N_SECTORS; sno++) {
13236c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sec = &sectors[sno];
13246c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (sec->tc == NULL)
13256c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            continue;
13266c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         anyDeleted |= delete_translations_in_sector(
13276c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj                         sec, guest_start, range );
13286c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
13296c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
1330de4a1d01951937632098a6cda45859afa587a06fsewardj   }
1331de4a1d01951937632098a6cda45859afa587a06fsewardj
1332fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (anyDeleted)
1333fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      invalidateFastCache();
13346c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
13350ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   /* don't forget the no-redir cache */
13360ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredir_discard_translations( guest_start, range );
13370ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13386c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   /* Post-deletion sanity check */
13396c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (VG_(clo_sanity_level >= 4)) {
13406c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      Int      i;
13416c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      TTEntry* tte;
13426c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      Bool     sane = sanity_check_all_sectors();
13436c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      vg_assert(sane);
13446c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      /* But now, also check the requested address range isn't
13456c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         present anywhere. */
13466c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (sno = 0; sno < N_SECTORS; sno++) {
13476c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sec = &sectors[sno];
13486c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (sec->tc == NULL)
13496c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            continue;
13506c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         for (i = 0; i < N_TTES_PER_SECTOR; i++) {
13516c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            tte = &sec->tt[i];
13526c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            if (tte->status != InUse)
13536c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj               continue;
13546c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            vg_assert(!overlaps( guest_start, range, &tte->vge ));
13556c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         }
13566c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
13576c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
1358fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj}
13596c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
13606c3769f487145a08c01b58d6e5db3ba274062ad4sewardj
1361fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
13620ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/*--- AUXILIARY: the unredirected TT/TC                    ---*/
13630ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/*------------------------------------------------------------*/
13640ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13650ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/* A very simple translation cache which holds a small number of
13660ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredirected translations.  This is completely independent of the
13670ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   main tt/tc structures.  When unredir_tc or unredir_tt becomes full,
13680ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   both structures are simply dumped and we start over.
13690ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13700ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   Since these translations are unredirected, the search key is (by
13710ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   definition) the first address entry in the .vge field. */
13720ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13730ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/* Sized to hold 500 translations of average size 1000 bytes. */
13740ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13750ec07f32bbbb209d749b9974408e6f025ad40b31sewardj#define UNREDIR_SZB   1000
13760ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13770ec07f32bbbb209d749b9974408e6f025ad40b31sewardj#define N_UNREDIR_TT  500
13780ec07f32bbbb209d749b9974408e6f025ad40b31sewardj#define N_UNREDIR_TCQ (N_UNREDIR_TT * UNREDIR_SZB / sizeof(ULong))
13790ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13800ec07f32bbbb209d749b9974408e6f025ad40b31sewardjtypedef
13810ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   struct {
13820ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      VexGuestExtents vge;
13830ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      Addr            hcode;
13840ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      Bool            inUse;
13850ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   }
13860ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   UTCEntry;
13870ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13880ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/* We just allocate forwards in _tc, never deleting. */
138978c0c09d429c95115e826ef769ecaa6cff2ac338tomstatic ULong    *unredir_tc;
139078c0c09d429c95115e826ef769ecaa6cff2ac338tomstatic Int      unredir_tc_used = N_UNREDIR_TCQ;
13910ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
13920ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/* Slots in _tt can come into use and out again (.inUse).
13930ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   Nevertheless _tt_highwater is maintained so that invalidations
13940ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   don't have to scan all the slots when only a few are in use.
13950ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   _tt_highwater holds the index of the highest ever allocated
13960ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   slot. */
13970ec07f32bbbb209d749b9974408e6f025ad40b31sewardjstatic UTCEntry unredir_tt[N_UNREDIR_TT];
13980ec07f32bbbb209d749b9974408e6f025ad40b31sewardjstatic Int      unredir_tt_highwater;
13990ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14000ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14010ec07f32bbbb209d749b9974408e6f025ad40b31sewardjstatic void init_unredir_tt_tc ( void )
14020ec07f32bbbb209d749b9974408e6f025ad40b31sewardj{
14030ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   Int i;
140478c0c09d429c95115e826ef769ecaa6cff2ac338tom   if (unredir_tc == NULL) {
1405cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      SysRes sres = VG_(am_mmap_anon_float_valgrind)
1406cda2f0fbda4c4b2644babc830244be8aed95de1dnjn                       ( N_UNREDIR_TT * UNREDIR_SZB );
1407cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      if (sr_isError(sres)) {
1408cda2f0fbda4c4b2644babc830244be8aed95de1dnjn         VG_(out_of_memory_NORETURN)("init_unredir_tt_tc",
1409cda2f0fbda4c4b2644babc830244be8aed95de1dnjn                                     N_UNREDIR_TT * UNREDIR_SZB);
141078c0c09d429c95115e826ef769ecaa6cff2ac338tom         /*NOTREACHED*/
141178c0c09d429c95115e826ef769ecaa6cff2ac338tom      }
1412cda2f0fbda4c4b2644babc830244be8aed95de1dnjn      unredir_tc = (ULong *)(AddrH)sr_Res(sres);
141378c0c09d429c95115e826ef769ecaa6cff2ac338tom   }
14140ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredir_tc_used = 0;
14150ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   for (i = 0; i < N_UNREDIR_TT; i++)
14160ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      unredir_tt[i].inUse = False;
14170ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredir_tt_highwater = -1;
14180ec07f32bbbb209d749b9974408e6f025ad40b31sewardj}
14190ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14200ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/* Do a sanity check; return False on failure. */
14210ec07f32bbbb209d749b9974408e6f025ad40b31sewardjstatic Bool sanity_check_redir_tt_tc ( void )
14220ec07f32bbbb209d749b9974408e6f025ad40b31sewardj{
14230ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   Int i;
14240ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   if (unredir_tt_highwater < -1) return False;
14250ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   if (unredir_tt_highwater >= N_UNREDIR_TT) return False;
14260ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14270ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   for (i = unredir_tt_highwater+1; i < N_UNREDIR_TT; i++)
14280ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      if (unredir_tt[i].inUse)
14290ec07f32bbbb209d749b9974408e6f025ad40b31sewardj         return False;
14300ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14310ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   if (unredir_tc_used < 0) return False;
14320ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   if (unredir_tc_used > N_UNREDIR_TCQ) return False;
14330ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14340ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   return True;
14350ec07f32bbbb209d749b9974408e6f025ad40b31sewardj}
14360ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14370ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14380ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/* Add an UNREDIRECTED translation of vge to TT/TC.  The translation
14390ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   is temporarily in code[0 .. code_len-1].
14400ec07f32bbbb209d749b9974408e6f025ad40b31sewardj*/
14410ec07f32bbbb209d749b9974408e6f025ad40b31sewardjvoid VG_(add_to_unredir_transtab)( VexGuestExtents* vge,
14420ec07f32bbbb209d749b9974408e6f025ad40b31sewardj                                   Addr64           entry,
14430ec07f32bbbb209d749b9974408e6f025ad40b31sewardj                                   AddrH            code,
14441dcee097db02f9ef3ba355162c4373d90d0e895cnjn                                   UInt             code_len )
14450ec07f32bbbb209d749b9974408e6f025ad40b31sewardj{
14460ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   Int   i, j, code_szQ;
14470ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   HChar *srcP, *dstP;
14480ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14490ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(sanity_check_redir_tt_tc());
14500ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14510ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   /* This is the whole point: it's not redirected! */
14520ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(entry == vge->base[0]);
14530ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14540ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   /* How many unredir_tt slots are needed */
14550ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   code_szQ = (code_len + 7) / 8;
14560ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14570ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   /* Look for an empty unredir_tc slot */
14580ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   for (i = 0; i < N_UNREDIR_TT; i++)
14590ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      if (!unredir_tt[i].inUse)
14600ec07f32bbbb209d749b9974408e6f025ad40b31sewardj         break;
14610ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14620ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   if (i >= N_UNREDIR_TT || code_szQ > (N_UNREDIR_TCQ - unredir_tc_used)) {
14630ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      /* It's full; dump everything we currently have */
14640ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      init_unredir_tt_tc();
14650ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      i = 0;
14660ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   }
14670ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14680ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(unredir_tc_used >= 0);
14690ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(unredir_tc_used <= N_UNREDIR_TCQ);
14700ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(code_szQ > 0);
14710ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(code_szQ + unredir_tc_used <= N_UNREDIR_TCQ);
14720ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(i >= 0 && i < N_UNREDIR_TT);
14730ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(unredir_tt[i].inUse == False);
14740ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14750ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   if (i > unredir_tt_highwater)
14760ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      unredir_tt_highwater = i;
14770ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14780ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   dstP = (HChar*)&unredir_tc[unredir_tc_used];
14790ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   srcP = (HChar*)code;
14800ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   for (j = 0; j < code_len; j++)
14810ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      dstP[j] = srcP[j];
14820ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
1483c0a02f88a9b5ca7cebebf67e1f2f5ebcadb1e238sewardj   invalidate_icache( dstP, code_len );
1484c0a02f88a9b5ca7cebebf67e1f2f5ebcadb1e238sewardj
14850ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredir_tt[i].inUse = True;
14860ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredir_tt[i].vge   = *vge;
14870ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredir_tt[i].hcode = (Addr)dstP;
14880ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14890ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   unredir_tc_used += code_szQ;
14900ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(unredir_tc_used >= 0);
14910ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(unredir_tc_used <= N_UNREDIR_TCQ);
14920ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14930ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(&dstP[code_len] <= (HChar*)&unredir_tc[unredir_tc_used]);
14940ec07f32bbbb209d749b9974408e6f025ad40b31sewardj}
14950ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
14960ec07f32bbbb209d749b9974408e6f025ad40b31sewardjBool VG_(search_unredir_transtab) ( /*OUT*/AddrH* result,
14970ec07f32bbbb209d749b9974408e6f025ad40b31sewardj                                    Addr64        guest_addr )
14980ec07f32bbbb209d749b9974408e6f025ad40b31sewardj{
14990ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   Int i;
15000ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   for (i = 0; i < N_UNREDIR_TT; i++) {
15010ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      if (!unredir_tt[i].inUse)
15020ec07f32bbbb209d749b9974408e6f025ad40b31sewardj         continue;
15030ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      if (unredir_tt[i].vge.base[0] == guest_addr) {
15040ec07f32bbbb209d749b9974408e6f025ad40b31sewardj         *result = (AddrH)unredir_tt[i].hcode;
15050ec07f32bbbb209d749b9974408e6f025ad40b31sewardj         return True;
15060ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      }
15070ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   }
15080ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   return False;
15090ec07f32bbbb209d749b9974408e6f025ad40b31sewardj}
15100ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
15110ec07f32bbbb209d749b9974408e6f025ad40b31sewardjstatic void unredir_discard_translations( Addr64 guest_start, ULong range )
15120ec07f32bbbb209d749b9974408e6f025ad40b31sewardj{
15130ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   Int i;
15140ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
15150ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   vg_assert(sanity_check_redir_tt_tc());
15160ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
15170ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   for (i = 0; i <= unredir_tt_highwater; i++) {
15180ec07f32bbbb209d749b9974408e6f025ad40b31sewardj      if (unredir_tt[i].inUse
15190ec07f32bbbb209d749b9974408e6f025ad40b31sewardj          && overlaps( guest_start, range, &unredir_tt[i].vge))
15200ec07f32bbbb209d749b9974408e6f025ad40b31sewardj         unredir_tt[i].inUse = False;
15210ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   }
15220ec07f32bbbb209d749b9974408e6f025ad40b31sewardj}
15230ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
15240ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
15250ec07f32bbbb209d749b9974408e6f025ad40b31sewardj/*------------------------------------------------------------*/
1526fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Initialisation.                                      ---*/
1527fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
1528fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1529fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid VG_(init_tt_tc) ( void )
15306c3769f487145a08c01b58d6e5db3ba274062ad4sewardj{
15316c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   Int i, j, avg_codeszQ;
1532de4a1d01951937632098a6cda45859afa587a06fsewardj
1533663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   vg_assert(!init_done);
1534663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj   init_done = True;
1535663a1bd7a8def9d4ef4a10615732a15cc9b09171sewardj
1536fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Otherwise lots of things go wrong... */
1537fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sizeof(ULong) == 8);
1538fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(sizeof(Addr64) == 8);
15395f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   /* check fast cache entries really are 2 words long */
15405f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(sizeof(Addr) == sizeof(void*));
15415f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(sizeof(FastCacheEntry) == 2 * sizeof(Addr));
15425f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   /* check fast cache entries are packed back-to-back with no spaces */
15435f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(sizeof( VG_(tt_fast) ) == VG_TT_FAST_SIZE * sizeof(FastCacheEntry));
15445f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   /* check fast cache is aligned as we requested.  Not fatal if it
15455f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      isn't, but we might as well make sure. */
15465f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   vg_assert(VG_IS_16_ALIGNED( ((Addr) & VG_(tt_fast)[0]) ));
1547de4a1d01951937632098a6cda45859afa587a06fsewardj
1548fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (VG_(clo_verbosity) > 2)
1549fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(message)(Vg_DebugMsg,
1550fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                   "TT/TC: VG_(init_tt_tc) "
1551738856f99eea33d86ce91dcb1d6cd5b151e307casewardj                   "(startup of code management)\n");
1552fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1553fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Figure out how big each tc area should be.  */
155443b9a8abb139b86a24457fa3c19b9cb60ca17c3anjn   avg_codeszQ   = (VG_(details).avg_translation_sizeB + 7) / 8;
155543b9a8abb139b86a24457fa3c19b9cb60ca17c3anjn   tc_sector_szQ = N_TTES_PER_SECTOR_USABLE * (1 + avg_codeszQ);
1556fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1557fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Ensure the calculated value is not way crazy. */
1558fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   vg_assert(tc_sector_szQ >= 2 * N_TTES_PER_SECTOR_USABLE);
1559e808930793aeddc4cfd3e7a94b665913bec2566csewardj   vg_assert(tc_sector_szQ <= 80 * N_TTES_PER_SECTOR_USABLE);
1560fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1561fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* Initialise the sectors */
1562fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   youngest_sector = 0;
1563fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (i = 0; i < N_SECTORS; i++) {
1564fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tc = NULL;
1565fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tt = NULL;
1566fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tc_next = NULL;
1567fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      sectors[i].tt_n_inuse = 0;
15686c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (j = 0; j < ECLASS_N; j++) {
15696c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sectors[i].ec2tte_size[j] = 0;
15706c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sectors[i].ec2tte_used[j] = 0;
15716c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         sectors[i].ec2tte[j] = NULL;
15726c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
15736c3769f487145a08c01b58d6e5db3ba274062ad4sewardj   }
15744ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
15755d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   /* Initialise the sector_search_order hint table. */
15765d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj   for (i = 0; i < N_SECTORS; i++)
15775d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj      sector_search_order[i] = -1;
15785d0d1f3a78d6c5c765360982a08d87a068ce7f1csewardj
15795f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   /* Initialise the fast caches.  If not profiling (the usual case),
15805f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      we have to explicitly invalidate the fastN cache as
15815f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      invalidateFastCache() won't do that for us. */
1582fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   invalidateFastCache();
15835f76de086a6d643db51e50a4e623df7dfc9b6161sewardj   if (VG_(clo_profile_flags) == 0)
15845f76de086a6d643db51e50a4e623df7dfc9b6161sewardj      invalidateFastNCache();
1585fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
15860ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   /* and the unredir tt/tc */
15870ec07f32bbbb209d749b9974408e6f025ad40b31sewardj   init_unredir_tt_tc();
15880ec07f32bbbb209d749b9974408e6f025ad40b31sewardj
1589fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   if (VG_(clo_verbosity) > 2) {
1590fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(message)(Vg_DebugMsg,
1591738856f99eea33d86ce91dcb1d6cd5b151e307casewardj         "TT/TC: cache: %d sectors of %d bytes each = %d total\n",
1592fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj          N_SECTORS, 8 * tc_sector_szQ,
1593fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj          N_SECTORS * 8 * tc_sector_szQ );
1594fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      VG_(message)(Vg_DebugMsg,
1595738856f99eea33d86ce91dcb1d6cd5b151e307casewardj         "TT/TC: table: %d total entries, max occupancy %d (%d%%)\n",
1596fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         N_SECTORS * N_TTES_PER_SECTOR,
1597fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         N_SECTORS * N_TTES_PER_SECTOR_USABLE,
1598fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         SECTOR_TT_LIMIT_PERCENT );
1599fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   }
160045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
160145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "transtab",
160245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      "cache: %d sectors of %d bytes each = %d total\n",
160345f4e7c91119c7d01a59f5e827c67841632c9314sewardj       N_SECTORS, 8 * tc_sector_szQ,
160445f4e7c91119c7d01a59f5e827c67841632c9314sewardj       N_SECTORS * 8 * tc_sector_szQ );
160545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(2, "transtab",
160645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      "table: %d total entries, max occupancy %d (%d%%)\n",
160745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      N_SECTORS * N_TTES_PER_SECTOR,
160845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      N_SECTORS * N_TTES_PER_SECTOR_USABLE,
160945f4e7c91119c7d01a59f5e827c67841632c9314sewardj      SECTOR_TT_LIMIT_PERCENT );
1610de4a1d01951937632098a6cda45859afa587a06fsewardj}
1611de4a1d01951937632098a6cda45859afa587a06fsewardj
16124ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
1613fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
1614fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Printing out statistics.                             ---*/
1615fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
1616fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1617fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic ULong safe_idiv( ULong a, ULong b )
161892e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote{
161992e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   return (b == 0 ? 0 : a / b);
162092e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote}
162192e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote
1622fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjUInt VG_(get_bbs_translated) ( void )
1623fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj{
1624fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return n_in_count;
1625fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj}
1626fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1627fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjvoid VG_(print_tt_tc_stats) ( void )
162892e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote{
162992e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
1630738856f99eea33d86ce91dcb1d6cd5b151e307casewardj      "    tt/tc: %'llu tt lookups requiring %'llu probes\n",
1631fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      n_full_lookups, n_lookup_probes );
163292e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
1633738856f99eea33d86ce91dcb1d6cd5b151e307casewardj      "    tt/tc: %'llu fast-cache updates, %'llu flushes\n",
1634fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      n_fast_updates, n_fast_flushes );
1635fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
163692e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
1637a0b6b2cf9abc7b0d87be1215a245eaccc0452af9bart                " transtab: new        %'lld "
1638738856f99eea33d86ce91dcb1d6cd5b151e307casewardj                "(%'llu -> %'llu; ratio %'llu:10) [%'llu scs]\n",
1639fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                n_in_count, n_in_osize, n_in_tsize,
164026412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj                safe_idiv(10*n_in_tsize, n_in_osize),
164126412bd2c4ef3e55683141f132ebd1eb32d8530bsewardj                n_in_sc_count);
164292e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote   VG_(message)(Vg_DebugMsg,
1643738856f99eea33d86ce91dcb1d6cd5b151e307casewardj                " transtab: dumped     %'llu (%'llu -> ?" "?)\n",
1644fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                n_dump_count, n_dump_osize );
1645fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   VG_(message)(Vg_DebugMsg,
1646738856f99eea33d86ce91dcb1d6cd5b151e307casewardj                " transtab: discarded  %'llu (%'llu -> ?" "?)\n",
1647fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                n_disc_count, n_disc_osize );
16486c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj
16496c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   if (0) {
16506c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      Int i;
16516c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      VG_(printf)("\n");
16526c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      for (i = 0; i < ECLASS_N; i++) {
16536c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         VG_(printf)(" %4d", sectors[0].ec2tte_used[i]);
16546c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj         if (i % 16 == 15)
16556c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj            VG_(printf)("\n");
16566c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      }
16576c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj      VG_(printf)("\n\n");
16586c1bbbb1799cc34d05e2c1bae06f5533151eaaa3sewardj   }
165992e7b7f3d93564e293483fcf0f52f2d6f6c6dcc0nethercote}
1660de4a1d01951937632098a6cda45859afa587a06fsewardj
1661fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
1662fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*--- Printing out of profiling results.                   ---*/
1663fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj/*------------------------------------------------------------*/
16644ccf707a1b52898b878fc90dc0054a0c23cc9fccsewardj
1665fa8ec113ecff891bdefb13dd361b40a503a992f8sewardjstatic ULong score ( TTEntry* tte )
1666fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj{
1667fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   return ((ULong)tte->weight) * ((ULong)tte->count);
1668de4a1d01951937632098a6cda45859afa587a06fsewardj}
1669de4a1d01951937632098a6cda45859afa587a06fsewardj
16702025cf98a3210c175a90fc77cb599cca1643bd68njnULong VG_(get_BB_profile) ( BBProfEntry tops[], UInt n_tops )
1671de4a1d01951937632098a6cda45859afa587a06fsewardj{
1672fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   Int   sno, i, r, s;
16732025cf98a3210c175a90fc77cb599cca1643bd68njn   ULong score_total;
1674fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1675fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   /* First, compute the total weighted count, and find the top N
16762025cf98a3210c175a90fc77cb599cca1643bd68njn      ttes.  tops contains pointers to the most-used n_tops blocks, in
1677fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      descending order (viz, tops[0] is the highest scorer). */
16782025cf98a3210c175a90fc77cb599cca1643bd68njn   for (i = 0; i < n_tops; i++) {
16792025cf98a3210c175a90fc77cb599cca1643bd68njn      tops[i].addr  = 0;
16802025cf98a3210c175a90fc77cb599cca1643bd68njn      tops[i].score = 0;
16812025cf98a3210c175a90fc77cb599cca1643bd68njn   }
1682fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1683fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   score_total = 0;
1684fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj
1685fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj   for (sno = 0; sno < N_SECTORS; sno++) {
1686fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      if (sectors[sno].tc == NULL)
168718d7513cc08bf982711c8a22b70d56af6aa87b33sewardj         continue;
1688fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj      for (i = 0; i < N_TTES_PER_SECTOR; i++) {
1689fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         if (sectors[sno].tt[i].status != InUse)
1690fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            continue;
1691fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         score_total += score(&sectors[sno].tt[i]);
1692fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         /* Find the rank for sectors[sno].tt[i]. */
16932025cf98a3210c175a90fc77cb599cca1643bd68njn         r = n_tops-1;
1694fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         while (True) {
1695fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            if (r == -1)
1696fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               break;
16972025cf98a3210c175a90fc77cb599cca1643bd68njn             if (tops[r].addr == 0) {
1698fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               r--;
1699fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               continue;
1700fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             }
17012025cf98a3210c175a90fc77cb599cca1643bd68njn             if ( score(&sectors[sno].tt[i]) > tops[r].score ) {
1702fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                r--;
1703fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj                continue;
1704fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             }
1705fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj             break;
1706fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
1707fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         r++;
17082025cf98a3210c175a90fc77cb599cca1643bd68njn         vg_assert(r >= 0 && r <= n_tops);
1709fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         /* This bb should be placed at r, and bbs above it shifted
1710fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj            upwards one slot. */
17112025cf98a3210c175a90fc77cb599cca1643bd68njn         if (r < n_tops) {
17122025cf98a3210c175a90fc77cb599cca1643bd68njn            for (s = n_tops-1; s > r; s--)
1713fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj               tops[s] = tops[s-1];
17142025cf98a3210c175a90fc77cb599cca1643bd68njn            tops[r].addr  = sectors[sno].tt[i].entry;
17152025cf98a3210c175a90fc77cb599cca1643bd68njn            tops[r].score = score( &sectors[sno].tt[i] );
1716fa8ec113ecff891bdefb13dd361b40a503a992f8sewardj         }
1717de4a1d01951937632098a6cda45859afa587a06fsewardj      }
1718de4a1d01951937632098a6cda45859afa587a06fsewardj   }
1719de4a1d01951937632098a6cda45859afa587a06fsewardj
17202025cf98a3210c175a90fc77cb599cca1643bd68njn   return score_total;
1721c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj}
1722c0d8f68810eb79a5a6cb6049d6a4ab1de7dc4e18sewardj
1723de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
17248bddf58af8cc7342d4bde6712c5a6a33bf2850d4njn/*--- end                                                          ---*/
1725de4a1d01951937632098a6cda45859afa587a06fsewardj/*--------------------------------------------------------------------*/
1726