1436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* -*- mode: C; c-basic-offset: 3; -*- */
2436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
3436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
4436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--- Cache-related stuff.                               m_cache.c ---*/
5436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
6436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
7436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*
8436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   This file is part of Valgrind, a dynamic binary instrumentation
9436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   framework.
10436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2002-2013 Nicholas Nethercote
12436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      njn@valgrind.org
13436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
14436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   This program is free software; you can redistribute it and/or
15436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   modify it under the terms of the GNU General Public License as
16436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   published by the Free Software Foundation; either version 2 of the
17436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   License, or (at your option) any later version.
18436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
19436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   This program is distributed in the hope that it will be useful, but
20436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   WITHOUT ANY WARRANTY; without even the implied warranty of
21436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   General Public License for more details.
23436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
24436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   You should have received a copy of the GNU General Public License
25436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   along with this program; if not, write to the Free Software
26436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   02111-1307, USA.
28436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
29436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   The GNU General Public License is contained in the file COPYING.
30436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov*/
31436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
32436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_basics.h"
33436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcbase.h"
34436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcassert.h"
35436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_libcprint.h"
36436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_mallocfree.h"
37436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_machine.h"
38436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_debuglog.h"
39436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "libvex.h"
40436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
41436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#if defined(VGA_x86) || defined(VGA_amd64)
42436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
43436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "pub_core_cpuid.h"
44436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
45436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov// All CPUID info taken from sandpile.org/ia32/cpuid.htm */
46436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov// Probably only works for Intel and AMD chips, and probably only for some of
47436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov// them.
48436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
49436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void
50436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovadd_cache(VexCacheInfo *ci, VexCache cache)
51436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
52436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static UInt num_allocated = 0;
53436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
54436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (ci->num_caches == num_allocated) {
55436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      num_allocated += 6;
56436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches = VG_(realloc)("m_cache", ci->caches,
57436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                num_allocated * sizeof *ci->caches);
58436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
59436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
60436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (ci->num_levels < cache.level) ci->num_levels = cache.level;
61436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->caches[ci->num_caches++] = cache;
62436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
63436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
64436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Convenience macros */
65436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_icache(level, size, assoc, linesize) \
66436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   do { \
67436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      add_cache(ci, \
68436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                VEX_CACHE_INIT(INSN_CACHE, level, size, linesize, assoc)); \
69436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } while (0)
70436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
71436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_dcache(level, size, assoc, linesize) \
72436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   do { \
73436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      add_cache(ci, \
74436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                VEX_CACHE_INIT(DATA_CACHE, level, size, linesize, assoc)); \
75436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } while (0)
76436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
77436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_ucache(level, size, assoc, linesize) \
78436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   do { \
79436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      add_cache(ci, \
80436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                VEX_CACHE_INIT(UNIFIED_CACHE, level, size, linesize, assoc)); \
81436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } while (0)
82436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
83436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_itcache(level, size, assoc) \
84436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   do { \
85436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VexCache c = \
86436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          VEX_CACHE_INIT(INSN_CACHE, level, size, 0, assoc); \
87436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      c.is_trace_cache = True; \
88436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      add_cache(ci, c); \
89436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } while (0)
90436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
91436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_I1(size, assoc, linesize) add_icache(1, size, assoc, linesize)
92436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_D1(size, assoc, linesize) add_dcache(1, size, assoc, linesize)
93436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_U1(size, assoc, linesize) add_ucache(1, size, assoc, linesize)
94436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_I2(size, assoc, linesize) add_icache(2, size, assoc, linesize)
95436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_D2(size, assoc, linesize) add_dcache(2, size, assoc, linesize)
96436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_U2(size, assoc, linesize) add_ucache(2, size, assoc, linesize)
97436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_I3(size, assoc, linesize) add_icache(3, size, assoc, linesize)
98436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_D3(size, assoc, linesize) add_dcache(3, size, assoc, linesize)
99436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_U3(size, assoc, linesize) add_ucache(3, size, assoc, linesize)
100436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
101436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define add_I1T(size, assoc) \
102436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   add_itcache(1, size, assoc)
103436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
104436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Intel method is truly wretched.  We have to do an insane indexing into an
105436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * array of pre-defined configurations for various parts of the memory
106436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * hierarchy.
107436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * According to Intel Processor Identification, App Note 485.
108436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *
109436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * If a L3 cache is found, then data for it rather than the L2
110436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * is returned via *LLc.
111436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov */
112436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int
113436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovIntel_cache_info(Int level, VexCacheInfo *ci)
114436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
115436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt cpuid1_eax;
116436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt cpuid1_ignore;
117436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int family;
118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int model;
119436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UChar info[16];
120436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int   i, j, trials;
121436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
122436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (level < 2) {
123436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "warning: CPUID level < 2 for Intel "
124436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    "processor (%d)\n", level);
125436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return -1;
126436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
127436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
128436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* family/model needed to distinguish code reuse (currently 0x49) */
129436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(cpuid)(1, 0, &cpuid1_eax, &cpuid1_ignore,
130436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	      &cpuid1_ignore, &cpuid1_ignore);
131436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   family = (((cpuid1_eax >> 20) & 0xff) << 4) + ((cpuid1_eax >> 8) & 0xf);
132436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   model =  (((cpuid1_eax >> 16) & 0xf) << 4) + ((cpuid1_eax >> 4) & 0xf);
133436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
134436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(cpuid)(2, 0, (UInt*)&info[0], (UInt*)&info[4],
135436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    (UInt*)&info[8], (UInt*)&info[12]);
136436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   trials  = info[0] - 1;   /* AL register - bits 0..7 of %eax */
137436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   info[0] = 0x0;           /* reset AL */
138436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
139436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0 != trials) {
140436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "warning: non-zero CPUID trials for Intel "
141436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    "processor (%d)\n", trials);
142436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return -1;
143436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
144436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
145436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->num_levels = 0;
146436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->num_caches = 0;
147436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->icaches_maintain_coherence = True;
148436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->caches = NULL;
149436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
150436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i < 16; i++) {
151436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
152436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (info[i]) {
153436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
154436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x0:       /* ignore zeros */
155436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          break;
156436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
157436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* TLB info, ignore */
158436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
159436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x0b:
160436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x4f: case 0x50: case 0x51: case 0x52: case 0x55:
161436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x56: case 0x57: case 0x59:
162436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x5a: case 0x5b: case 0x5c: case 0x5d:
163436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x76:
164436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xb0: case 0xb1: case 0xb2:
165436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xb3: case 0xb4: case 0xba: case 0xc0:
166436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xca:
167436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          break;
168436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
169436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x06: add_I1( 8, 4, 32); break;
170436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x08: add_I1(16, 4, 32); break;
171436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x09: add_I1(32, 4, 64); break;
172436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x30: add_I1(32, 8, 64); break;
173436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
174436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x0a: add_D1( 8, 2, 32); break;
175436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x0c: add_D1(16, 4, 32); break;
176436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x0d: add_D1(16, 4, 64); break;
177436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x0e: add_D1(24, 6, 64); break;
178436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x2c: add_D1(32, 8, 64); break;
179436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
180436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* IA-64 info -- panic! */
181436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x10: case 0x15: case 0x1a:
182436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x88: case 0x89: case 0x8a: case 0x8d:
183436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x90: case 0x96: case 0x9b:
184436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(core_panic)("IA-64 cache detected?!");
185436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
186436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* L3 cache info. */
187436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x22: add_U3(512,    4, 64); break;
188436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x23: add_U3(1024,   8, 64); break;
189436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x25: add_U3(2048,   8, 64); break;
190436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x29: add_U3(4096,   8, 64); break;
191436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x46: add_U3(4096,   4, 64); break;
192436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x47: add_U3(8192,   8, 64); break;
193436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x4a: add_U3(6144,  12, 64); break;
194436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x4b: add_U3(8192,  16, 64); break;
195436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x4c: add_U3(12288, 12, 64); break;
196436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x4d: add_U3(16384, 16, 64); break;
197436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xd0: add_U3(512,    4, 64); break;
198436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xd1: add_U3(1024,   4, 64); break;
199436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xd2: add_U3(2048,   4, 64); break;
200436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xd6: add_U3(1024,   8, 64); break;
201436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xd7: add_U3(2048,   8, 64); break;
202436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xd8: add_U3(4096,   8, 64); break;
203436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xdc: add_U3(1536,  12, 64); break;
204436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xdd: add_U3(3072,  12, 64); break;
205436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xde: add_U3(6144,  12, 64); break;
206436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xe2: add_U3(2048,  16, 64); break;
207436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xe3: add_U3(4096,  16, 64); break;
208436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xe4: add_U3(8192,  16, 64); break;
209436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xea: add_U3(12288, 24, 64); break;
210436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xeb: add_U3(18432, 24, 64); break;
211436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xec: add_U3(24576, 24, 64); break;
212436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
213436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Described as "MLC" in Intel documentation */
214436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x21: add_U2(256, 8, 64); break;
215436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
216436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* These are sectored, whatever that means */
217436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         // FIXME: I did not find these in the Intel docs
218436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x39: add_U2(128, 4, 64); break;
219436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x3c: add_U2(256, 4, 64); break;
220436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
221436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* If a P6 core, this means "no L2 cache".
222436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         If a P4 core, this means "no L3 cache".
223436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         We don't know what core it is, so don't issue a warning.  To detect
224436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         a missing L2 cache, we use 'L2_found'. */
225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x40:
226436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          break;
227436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
228436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x41: add_U2(  128,  4, 32); break;
229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x42: add_U2(  256,  4, 32); break;
230436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x43: add_U2(  512,  4, 32); break;
231436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x44: add_U2( 1024,  4, 32); break;
232436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x45: add_U2( 2048,  4, 32); break;
233436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x48: add_U2( 3072, 12, 64); break;
234436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x4e: add_U2( 6144, 24, 64); break;
235436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x49:
236436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (family == 15 && model == 6) {
237436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            /* On Xeon MP (family F, model 6), this is for L3 */
238436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            add_U3(4096, 16, 64);
239436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         } else {
240436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	    add_U2(4096, 16, 64);
241436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
242436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
243436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
244436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* These are sectored, whatever that means */
245436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x60: add_D1(16, 8, 64);  break;      /* sectored */
246436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x66: add_D1( 8, 4, 64);  break;      /* sectored */
247436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x67: add_D1(16, 4, 64);  break;      /* sectored */
248436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x68: add_D1(32, 4, 64);  break;      /* sectored */
249436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
250436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* HACK ALERT: Instruction trace cache -- capacity is micro-ops based.
251436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       * conversion to byte size is a total guess;  treat the 12K and 16K
252436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       * cases the same since the cache byte size must be a power of two for
253436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       * everything to work!.  Also guessing 32 bytes for the line size...
254436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       */
255436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x70:    /* 12K micro-ops, 8-way */
256436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         add_I1T(12, 8);
257436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
258436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x71:    /* 16K micro-ops, 8-way */
259436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         add_I1T(16, 8);
260436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
261436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x72:    /* 32K micro-ops, 8-way */
262436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         add_I1T(32, 8);
263436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
264436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
265436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* not sectored, whatever that might mean */
266436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x78: add_U2(1024, 4,  64);  break;
267436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
268436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* These are sectored, whatever that means */
269436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x79: add_U2( 128, 8,  64);  break;
270436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x7a: add_U2( 256, 8,  64);  break;
271436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x7b: add_U2( 512, 8,  64);  break;
272436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x7c: add_U2(1024, 8,  64);  break;
273436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x7d: add_U2(2048, 8,  64);  break;
274436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x7e: add_U2( 256, 8, 128);  break;
275436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x7f: add_U2( 512, 2,  64);  break;
276436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x80: add_U2( 512, 8,  64);  break;
277436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x81: add_U2( 128, 8,  32);  break;
278436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x82: add_U2( 256, 8,  32);  break;
279436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x83: add_U2( 512, 8,  32);  break;
280436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x84: add_U2(1024, 8,  32);  break;
281436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x85: add_U2(2048, 8,  32);  break;
282436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x86: add_U2( 512, 4,  64);  break;
283436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0x87: add_U2(1024, 8,  64);  break;
284436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
285436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Ignore prefetch information */
286436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xf0: case 0xf1:
287436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
288436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
289436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xff:
290436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         j = 0;
291436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(cpuid)(4, j++, (UInt*)&info[0], (UInt*)&info[4],
292436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                            (UInt*)&info[8], (UInt*)&info[12]);
293436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
294436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         while ((info[0] & 0x1f) != 0) {
295436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            UInt assoc = ((*(UInt *)&info[4] >> 22) & 0x3ff) + 1;
296436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            UInt parts = ((*(UInt *)&info[4] >> 12) & 0x3ff) + 1;
297436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            UInt line_size = (*(UInt *)&info[4] & 0x7ff) + 1;
298436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            UInt sets = *(UInt *)&info[8] + 1;
299436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
300436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            UInt size = assoc * parts * line_size * sets / 1024;
301436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
302436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            switch ((info[0] & 0xe0) >> 5)
303436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            {
304436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case 1:
305436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               switch (info[0] & 0x1f)
306436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               {
307436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 1: add_D1(size, assoc, line_size); break;
308436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 2: add_I1(size, assoc, line_size); break;
309436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 3: add_U1(size, assoc, line_size); break;
310436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               default:
311436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  VG_(debugLog)(1, "cache",
312436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                "warning: L1 cache of unknown type ignored\n");
313436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  break;
314436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               }
315436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               break;
316436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case 2:
317436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               switch (info[0] & 0x1f)
318436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               {
319436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 1: add_D2(size, assoc, line_size); break;
320436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 2: add_I2(size, assoc, line_size); break;
321436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 3: add_U2(size, assoc, line_size); break;
322436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               default:
323436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  VG_(debugLog)(1, "cache",
324436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                "warning: L2 cache of unknown type ignored\n");
325436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  break;
326436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               }
327436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               break;
328436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case 3:
329436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               switch (info[0] & 0x1f)
330436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               {
331436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 1: add_D3(size, assoc, line_size); break;
332436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 2: add_I3(size, assoc, line_size); break;
333436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               case 3: add_U3(size, assoc, line_size); break;
334436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               default:
335436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  VG_(debugLog)(1, "cache",
336436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                "warning: L3 cache of unknown type ignored\n");
337436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                  break;
338436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               }
339436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               break;
340436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            default:
341436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               VG_(debugLog)(1, "cache", "warning: L%u cache ignored\n",
342436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                             (info[0] & 0xe0) >> 5);
343436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               break;
344436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            }
345436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
346436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            VG_(cpuid)(4, j++, (UInt*)&info[0], (UInt*)&info[4],
347436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                               (UInt*)&info[8], (UInt*)&info[12]);
348436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
349436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
350436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
351436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      default:
352436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(debugLog)(1, "cache",
353436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       "warning: Unknown Intel cache config value (0x%x), "
354436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       "ignoring\n", info[i]);
355436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
356436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
357436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
358436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
359436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return 0;
360436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
361436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
362436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* AMD method is straightforward, just extract appropriate bits from the
363436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * result registers.
364436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *
365436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * Bits, for D1 and I1:
366436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *  31..24  data L1 cache size in KBs
367436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *  23..16  data L1 cache associativity (FFh=full)
368436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *  15.. 8  data L1 cache lines per tag
369436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *   7.. 0  data L1 cache line size in bytes
370436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *
371436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * Bits, for L2:
372436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *  31..16  unified L2 cache size in KBs
373436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *  15..12  unified L2 cache associativity (0=off, FFh=full)
374436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *  11.. 8  unified L2 cache lines per tag
375436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *   7.. 0  unified L2 cache line size in bytes
376436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *
377436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * #3  The AMD K7 processor's L2 cache must be configured prior to relying
378436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *     upon this information. (Whatever that means -- njn)
379436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *
380436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * Also, according to Cyrille Chepelov, Duron stepping A0 processors (model
381436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * 0x630) have a bug and misreport their L2 size as 1KB (it's really 64KB),
382436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * so we detect that.
383436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov *
384436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * Returns 0 on success, non-zero on failure.  As with the Intel code
385436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * above, if a L3 cache is found, then data for it rather than the L2
386436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * is returned via *LLc.
387436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov */
388436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
389436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* A small helper */
390436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int
391436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovdecode_AMD_cache_L2_L3_assoc ( Int bits_15_12 )
392436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
393436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Decode a L2/L3 associativity indication.  It is encoded
394436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      differently from the I1/D1 associativity.  Returns 1
395436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      (direct-map) as a safe but suboptimal result for unknown
396436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      encodings. */
397436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   switch (bits_15_12 & 0xF) {
398436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 1: return 1;    case 2: return 2;
399436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 4: return 4;    case 6: return 8;
400436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 8: return 16;   case 0xA: return 32;
401436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xB: return 48; case 0xC: return 64;
402436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xD: return 96; case 0xE: return 128;
403436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0xF: /* fully associative */
404436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0: /* L2/L3 cache or TLB is disabled */
405436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      default:
406436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        return 1;
407436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
408436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
409436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
410436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int
411436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovAMD_cache_info(VexCacheInfo *ci)
412436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
413436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt ext_level;
414436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt dummy, model;
415436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt I1i, D1i, L2i, L3i;
416436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt size, line_size, assoc;
417436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
418436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(cpuid)(0x80000000, 0, &ext_level, &dummy, &dummy, &dummy);
419436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
420436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0 == (ext_level & 0x80000000) || ext_level < 0x80000006) {
421436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "warning: ext_level < 0x80000006 for AMD "
422436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    "processor (0x%x)\n", ext_level);
423436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return -1;
424436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
425436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
426436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(cpuid)(0x80000005, 0, &dummy, &dummy, &D1i, &I1i);
427436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(cpuid)(0x80000006, 0, &dummy, &dummy, &L2i, &L3i);
428436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
429436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(cpuid)(0x1, 0, &model, &dummy, &dummy, &dummy);
430436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
431436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Check for Duron bug */
432436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (model == 0x630) {
433436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "warning: Buggy Duron stepping A0. "
434436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    "Assuming L2 size=65536 bytes\n");
435436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      L2i = (64 << 16) | (L2i & 0xffff);
436436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
437436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
438436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->num_levels = 2;
439436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->num_caches = 3;
440436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->icaches_maintain_coherence = True;
441436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
442436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Check for L3 cache */
443436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (((L3i >> 18) & 0x3fff) > 0) {
444436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->num_levels = 3;
445436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->num_caches = 4;
446436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
447436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
448436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->caches = VG_(malloc)("m_cache", ci->num_caches * sizeof *ci->caches);
449436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
450436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // D1
451436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   size      = (D1i >> 24) & 0xff;
452436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   assoc     = (D1i >> 16) & 0xff;
453436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   line_size = (D1i >>  0) & 0xff;
454436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->caches[0] = VEX_CACHE_INIT(DATA_CACHE, 1, size, line_size, assoc);
455436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
456436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // I1
457436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   size      = (I1i >> 24) & 0xff;
458436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   assoc     = (I1i >> 16) & 0xff;
459436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   line_size = (I1i >>  0) & 0xff;
460436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->caches[1] = VEX_CACHE_INIT(INSN_CACHE, 1, size, line_size, assoc);
461436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
462436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // L2    Nb: different bits used for L2
463436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   size      = (L2i >> 16) & 0xffff;
464436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   assoc     = decode_AMD_cache_L2_L3_assoc((L2i >> 12) & 0xf);
465436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   line_size = (L2i >>  0) & 0xff;
466436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->caches[2] = VEX_CACHE_INIT(UNIFIED_CACHE, 2, size, line_size, assoc);
467436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
468436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   // L3, if any
469436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (((L3i >> 18) & 0x3fff) > 0) {
470436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* There's an L3 cache. */
471436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* NB: the test in the if is "if L3 size > 0 ".  I don't know if
472436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         this is the right way to test presence-vs-absence of L3.  I
473436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         can't see any guidance on this in the AMD documentation. */
474436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      size      = ((L3i >> 18) & 0x3fff) * 512;
475436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assoc     = decode_AMD_cache_L2_L3_assoc((L3i >> 12) & 0xf);
476436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      line_size = (L3i >>  0) & 0xff;
477436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches[3] = VEX_CACHE_INIT(UNIFIED_CACHE, 3, size, line_size, assoc);
478436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
479436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
480436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return 0;
481436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
482436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
483436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int
484436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_caches_from_CPUID(VexCacheInfo *ci)
485436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
486436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int  ret, i;
487436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt level;
488436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar vendor_id[13];
489436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
490436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(VG_(has_cpuid)());
491436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
492436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(cpuid)(0, 0, &level, (UInt*)&vendor_id[0],
493436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	      (UInt*)&vendor_id[8], (UInt*)&vendor_id[4]);
494436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vendor_id[12] = '\0';
495436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
496436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0 == level) {    // CPUID level is 0, early Pentium?
497436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return -1;
498436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
499436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
500436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Only handling Intel and AMD chips... no Cyrix, Transmeta, etc */
501436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0 == VG_(strcmp)(vendor_id, "GenuineIntel")) {
502436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ret = Intel_cache_info(level, ci);
503436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
504436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else if (0 == VG_(strcmp)(vendor_id, "AuthenticAMD")) {
505436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ret = AMD_cache_info(ci);
506436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
507436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else if (0 == VG_(strcmp)(vendor_id, "CentaurHauls")) {
508436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Total kludge.  Pretend to be a VIA Nehemiah. */
509436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->num_levels = 2;
510436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->num_caches = 3;
511436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->icaches_maintain_coherence = True;
512436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches = VG_(malloc)("m_cache", ci->num_caches * sizeof *ci->caches);
513436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches[0] = VEX_CACHE_INIT(DATA_CACHE,    1, 64, 16, 16);
514436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches[1] = VEX_CACHE_INIT(INSN_CACHE,    1, 64, 16,  4);
515436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches[2] = VEX_CACHE_INIT(UNIFIED_CACHE, 2, 64, 16, 16);
516436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
517436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ret = 0;
518436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
519436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
520436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "CPU vendor ID not recognised (%s)\n",
521436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    vendor_id);
522436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return -1;
523436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
524436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
525436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Successful!  Convert sizes from KB to bytes */
526436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i < ci->num_caches; ++i) {
527436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches[i].sizeB *= 1024;
528436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
529436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
530436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return ret;
531436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
532436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
533436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool
534436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_cache_info(VexArchInfo *vai)
535436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
536436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int ret = get_caches_from_CPUID(&vai->hwcache_info);
537436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
538436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return ret == 0 ? True : False;
539436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
540436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
541436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGA_arm) || defined(VGA_ppc32) || defined(VGA_ppc64) || \
542436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   defined(VGA_mips32) || defined(VGA_mips64) || defined(VGA_arm64)
543436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
544436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool
545436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_cache_info(VexArchInfo *vai)
546436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
547436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vai->hwcache_info.icaches_maintain_coherence = False;
548436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
549436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return False;   // not yet
550436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
551436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
552436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGA_s390x)
553436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
554436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic ULong
555436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovecag(UInt ai, UInt li, UInt ti)
556436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
557436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   register ULong result asm("2") = 0;
558436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   register ULong input  asm("3") = (ai << 4) | (li << 1) | ti;
559436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
560436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   asm volatile(".short 0xeb20\n\t"
561436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                ".long  0x3000004c\n\t"
562436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                 : "=d" (result) : "d" (input));
563436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
564436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return result;
565436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
566436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
567436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic UInt
568436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_cache_info_for_level(ULong topology, UInt level)
569436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
570436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return (topology >> (56 - level * 8)) & 0xff;
571436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
572436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
573436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic ULong
574436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_line_size(UInt level, Bool is_insn_cache)
575436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
576436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return ecag(1, level, is_insn_cache);
577436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
578436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
579436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic ULong
580436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_total_size(UInt level, Bool is_insn_cache)
581436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
582436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return ecag(2, level, is_insn_cache);
583436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
584436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
585436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic ULong
586436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_associativity(UInt level, Bool is_insn_cache)
587436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
588436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return ecag(3, level, is_insn_cache);
589436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
590436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
591436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic VexCache
592436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_cache(UInt level, VexCacheKind kind)
593436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
594436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Bool is_insn_cache = kind == INSN_CACHE;
595436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt size = get_total_size(level, is_insn_cache);
596436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt line_size = get_line_size(level, is_insn_cache);
597436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt assoc = get_associativity(level, is_insn_cache);
598436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
599436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return VEX_CACHE_INIT(kind, level + 1, size, line_size, assoc);
600436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
601436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
602436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool
603436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovget_cache_info(VexArchInfo *vai)
604436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
605436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexCacheInfo *ci = &vai->hwcache_info;
606436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
607436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->icaches_maintain_coherence = True;
608436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
609436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (! (vai->hwcaps & VEX_HWCAPS_S390X_GIE)) {
610436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      // ECAG is not available
611436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return False;
612436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
613436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
614436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt level, cache_kind, info, i;
615436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ULong topology = ecag(0, 0, 0);   // get summary
616436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
617436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* ECAG supports at most 8 levels of cache. Find out how many levels
618436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      of cache and how many caches there are. */
619436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->num_levels = 0;
620436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->num_caches = 0;
621436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (level = 0; level < 8; level++) {
622436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      info = get_cache_info_for_level(topology, level);
623436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
624436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if ((info & 0xc) == 0) break;  // cache does not exist at this level
625436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ++ci->num_levels;
626436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
627436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      cache_kind = info & 0x3;
628436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (cache_kind) {
629436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0:  ci->num_caches += 2; break; /* separate data and insn cache */
630436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 1:  ci->num_caches += 1; break; /* only insn cache */
631436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 2:  ci->num_caches += 1; break; /* only data cache */
632436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 3:  ci->num_caches += 1; break; /* unified data and insn cache */
633436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
634436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
635436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
636436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ci->caches = VG_(malloc)("m_cache", ci->num_caches * sizeof *ci->caches);
637436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
638436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   i = 0;
639436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (level = 0; level < ci->num_levels; level++) {
640436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      info = get_cache_info_for_level(topology, level);
641436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      cache_kind = info & 0x3;
642436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (cache_kind) {
643436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 0:   /* separate data and insn cache */
644436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         ci->caches[i++] = get_cache(level, INSN_CACHE);
645436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         ci->caches[i++] = get_cache(level, DATA_CACHE);
646436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
647436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
648436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 1:   /* only insn cache */
649436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         ci->caches[i++] = get_cache(level, INSN_CACHE);
650436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
651436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
652436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 2:   /* only data cache */
653436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         ci->caches[i++] = get_cache(level, DATA_CACHE);
654436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
655436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
656436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case 3:   /* unified data and insn cache */
657436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         ci->caches[i++] = get_cache(level, UNIFIED_CACHE);
658436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
659436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
660436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
661436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return True;
662436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
663436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
664436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#else
665436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
666436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#error "Unknown arch"
667436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
668436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#endif
669436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
670436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Debug information */
671436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void
672436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovwrite_cache_info(const VexCacheInfo *ci)
673436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
674436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt i;
675436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
676436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(debugLog)(1, "cache", "Cache info:\n");
677436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(debugLog)(1, "cache", "  #levels = %u\n", ci->num_levels);
678436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(debugLog)(1, "cache", "  #caches = %u\n", ci->num_caches);
679436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (i = 0; i < ci->num_caches; ++i) {
680436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VexCache *c = ci->caches + i;
681436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar *kind;
682436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "     cache #%u:\n", i);
683436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      switch (c->kind) {
684436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case INSN_CACHE:    kind = "insn";    break;
685436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case DATA_CACHE:    kind = "data";    break;
686436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case UNIFIED_CACHE: kind = "unified"; break;
687436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      default: kind = "unknown"; break;
688436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
689436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "        kind = %s\n", kind);
690436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "        level = %u\n", c->level);
691436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "        size = %u bytes\n", c->sizeB);
692436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "        linesize = %u bytes\n", c->line_sizeB);
693436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "        assoc = %u\n", c->assoc);
694436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
695436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
696436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
697436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool
698436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovcache_info_is_sensible(const VexCacheInfo *ci)
699436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
700436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UInt level, i;
701436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Bool sensible = True;
702436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
703436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* There must be at most one cache of a given kind at the same level.
704436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      If there is a unified cache at a given level, no other cache may
705436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      exist at that level. */
706436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (level = 1; level <= ci->num_levels; ++level) {
707436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UInt num_icache, num_dcache, num_ucache;
708436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
709436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      num_icache = num_dcache = num_ucache = 0;
710436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      for (i = 0; i < ci->num_caches; ++i) {
711436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (ci->caches[i].level == level) {
712436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            switch (ci->caches[i].kind) {
713436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case INSN_CACHE:    ++num_icache; break;
714436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case DATA_CACHE:    ++num_dcache; break;
715436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case UNIFIED_CACHE: ++num_ucache; break;
716436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            }
717436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
718436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
719436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (num_icache == 0 && num_dcache == 0 && num_ucache == 0) {
720436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(debugLog)(1, "cache", "warning: No caches at level %u\n", level);
721436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         sensible = False;
722436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
723436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (num_icache > 1 || num_dcache > 1 || num_ucache > 1) {
724436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(debugLog)(1, "cache", "warning: More than one cache of a given "
725436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       "kind at level %u\n", level);
726436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         sensible = False;
727436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
728436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (num_ucache != 0 && (num_icache > 0 || num_dcache > 0)) {
729436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(debugLog)(1, "cache", "warning: Unified cache and I/D cache "
730436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       "at level %u\n", level);
731436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         sensible = False;
732436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
733436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
734436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
735436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* If there is a cache at level N > 1 there must be a cache at level N-1 */
736436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   for (level = 2; level <= ci->num_levels; ++level) {
737436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      Bool found = False;
738436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      for (i = 0; i < ci->num_caches; ++i) {
739436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (ci->caches[i].level == level - 1) {
740436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            found = True;
741436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            break;
742436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
743436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
744436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (! found) {
745436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(debugLog)(1, "cache", "warning: Cache at level %u but no cache "
746436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       "at level %u\n", level, level - 1);
747436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         sensible = False;
748436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
749436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
750436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
751436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return sensible;
752436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
753436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
754436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
755436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Autodetect the cache information for this host and stuff it into
756436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexArchInfo::hwcache_info. Return True if successful. */
757436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool
758436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovVG_(machine_get_cache_info)(VexArchInfo *vai)
759436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
760436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Bool ok = get_cache_info(vai);
761436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
762436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexCacheInfo *ci = &vai->hwcache_info;
763436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
764436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (! ok) {
765436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(debugLog)(1, "cache", "Could not autodetect cache info\n");
766436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
767436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ok = cache_info_is_sensible(ci);
768436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
769436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (! ok) {
770436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(debugLog)(1, "cache",
771436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       "Autodetected cache info is not sensible\n");
772436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      } else {
773436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(debugLog)(1, "cache",
774436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       "Autodetected cache info is sensible\n");
775436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      }
776436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      write_cache_info(ci);  /* write out for debugging */
777436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
778436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
779436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (! ok ) {
780436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Reset cache info */
781436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->num_levels = 0;
782436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->num_caches = 0;
783436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(free)(ci->caches);
784436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      ci->caches = NULL;
785436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
786436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
787436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return ok;
788436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
789436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
790436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
791436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--- end                                                          ---*/
792436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*--------------------------------------------------------------------*/
793