Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: ss_common.h | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | /* | |
24 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
25 | * Use is subject to license terms. | |
26 | */ | |
27 | ||
28 | #ifndef _SS_COMMON_H | |
29 | #define _SS_COMMON_H | |
30 | ||
31 | #pragma ident "@(#)ss_common.h 1.54 07/03/07 SMI" | |
32 | ||
33 | #ifdef __cplusplus | |
34 | extern "C" { | |
35 | #endif | |
36 | ||
37 | #include "basics.h" | |
38 | #include "fatal.h" | |
39 | #include "allocate.h" | |
40 | #include "simcore.h" | |
41 | #include "config.h" | |
42 | #include "options.h" | |
43 | #include "strutil.h" | |
44 | #include "fileutil.h" | |
45 | #include "lexer.h" | |
46 | #include "parser.h" | |
47 | #include "strings.h" | |
48 | #include "strutil.h" | |
49 | #include "createthr.h" | |
50 | #include "tsparcv9.h" | |
51 | #include "sparcv9regs.h" | |
52 | #include "tsparcv9internal.h" | |
53 | #include "execinstns.h" /* autogenerated core defined instructions */ | |
54 | #include "sparcv9decode.h" | |
55 | #include "sparcv9instns.h" /* autogenerated sparcv9 instruction definitions */ | |
56 | #include "xicache.h" | |
57 | #include "xdcache.h" | |
58 | #include "dumpinfo.h" | |
59 | #include "device.h" | |
60 | #include "callback.h" | |
61 | #include "bswap.h" | |
62 | ||
63 | ||
64 | #if 1 /* { */ | |
65 | #define RW_lock_t volatile int64_t | |
66 | #define RW_rdlock(_l) ss_rdlock(_l) | |
67 | #define RW_wrlock(_l) ss_wrlock(_l) | |
68 | #define RW_unlock(_l) ss_unlock(_l) | |
69 | #define RW_lock_init(_l, _a) do { *(_l) = 0; } while (0) | |
70 | extern void ss_rdlock(RW_lock_t *); | |
71 | extern void ss_wrlock(RW_lock_t *); | |
72 | extern void ss_unlock(RW_lock_t *); | |
73 | #elif HAS_POSIX_RW_LOCK /* } { */ | |
74 | #define RW_lock_t pthread_rwlock_t | |
75 | #define RW_rdlock(_l) pthread_rwlock_rdlock(_l) | |
76 | #define RW_wrlock(_l) pthread_rwlock_wrlock(_l) | |
77 | #define RW_unlock(_l) pthread_rwlock_unlock(_l) | |
78 | #define RW_lock_init(_l, _a) pthread_rwlock_init(_l, _a) | |
79 | #else /* } { */ | |
80 | #define RW_lock_t pthread_mutex_t | |
81 | #define RW_rdlock(_l) pthread_mutex_lock(_l) | |
82 | #define RW_wrlock(_l) pthread_mutex_lock(_l) | |
83 | #define RW_unlock(_l) pthread_mutex_unlock(_l) | |
84 | #define RW_lock_init(_l, _a) pthread_mutex_init(_l, _a) | |
85 | #endif /* } */ | |
86 | ||
87 | /* | |
88 | * SunSPARC / this file specific definitions | |
89 | */ | |
90 | ||
91 | #ifndef NDEBUG /* { */ | |
92 | #define DBG_CMP 0x100000000000LL | |
93 | #define DBGCMP(_s) do { if (debug_bits & DBG_CMP) { _s; } } while (0) | |
94 | #define DBG_TM 0x80000000000LL | |
95 | #define DBGTM(_s) do { if (debug_bits & DBG_TM) { _s; } } while (0) | |
96 | #define DBG_SCRATCH 0x10000000000LL | |
97 | #define DBGSCRATCH(_s) do { if (debug_bits & DBG_SCRATCH) { _s; } } while (0) | |
98 | #define DBG_DAE 0x8000000000LL | |
99 | #define DBGDAE(_s) do { if (debug_bits & DBG_DAE) { _s; } } while (0) | |
100 | #define DBG_LE 0x2000000LL | |
101 | #define DBGLE(_s) do { if (debug_bits & DBG_LE) { _s } } while (0) /* debug little endian */ | |
102 | #define DBG_ALIGN 0x4000000LL | |
103 | #define DBGALIGN(_s) do { if (debug_bits & DBG_ALIGN) { _s } } while (0) | |
104 | #define DBG_EPM 0x80LL | |
105 | #define DBGEPM(_s) do { if (debug_bits & DBG_EPM) { _s } } while (0) | |
106 | #define DBG_HCALL 0x8000LL | |
107 | #define DBGHC(s) do { if (debug_bits & DBG_HCALL) { s } } while (0) /* debug hcalls */ | |
108 | #define DBG_PIC 0x10000LL | |
109 | #define DBGPIC(s) do { if (debug_bits & DBG_PIC) { s } } while (0) /* debug Perf Cntrs */ | |
110 | #define DBG_SOFTINT 0x10000000LL | |
111 | #define DBGSOFTINT(s) do { if (debug_bits & DBG_SOFTINT) { s } } while (0) | |
112 | #define DBG_TICK 0x20000000LL | |
113 | #define DBGTICK(s) do { if (debug_bits & DBG_TICK) { s } } while (0) | |
114 | #define DBG_TICK_READ 0x4000000000LL | |
115 | #define DBGTICKREAD(s) do { if (debug_bits & DBG_TICK_READ) { s } } while (0) | |
116 | #define DBG_EXCEPT 0x20000LL | |
117 | #define DBGE(s) do { if (debug_bits & DBG_EXCEPT) { s } } while (0) /* debug exceptions */ | |
118 | #define DBG_HPSTATE 0x40000LL | |
119 | #define DBGHPS(s) do { if (debug_bits & DBG_HPSTATE) { s } } while (0) /* debug hpstate changes */ | |
120 | #define DBG_MMU 0x80000LL | |
121 | #define DBGMMU(s) do { if (debug_bits & DBG_MMU) { s } } while (0) /* debug mmu */ | |
122 | #define DBG_MISS 0x100000LL | |
123 | #define DBGMISS(s) do { if (debug_bits & DBG_MISS) { s } } while (0) /* debug mmu miss */ | |
124 | #define DBG_MC 0x200000LL | |
125 | #define DBGMC(s) do { if (debug_bits & DBG_MC) { s } } while (0) /* debug dram controllers */ | |
126 | #define DBG_TS 0x400000LL | |
127 | #define DBGTSTACK(s) do { if (debug_bits & DBG_TS) { s } } while (0) /* debug TSTATE etc. */ | |
128 | #define DBG_ERR 0x800000LL | |
129 | #define DBGERR(s) do { if (debug_bits & DBG_ERR) { s } } while (0) /* debug error injection */ | |
130 | #define DBG_SSI 0x1000000LL | |
131 | #define DBGSSI(s) do { if (debug_bits & DBG_SSI) { s } } while (0) /* debug SSI interrupts */ | |
132 | #define DBG_MONDO 0x8000000LL | |
133 | #define DBGMONDO(s) do { if (debug_bits & DBG_MONDO) { s } } while (0) /* debug mondo interrupts */ | |
134 | #define DBG_ERR_TRAP 0x200000000LL | |
135 | #define DBGERRTRAP(s) do { if (debug_bits & DBG_ERR_TRAP) { s } } while (0) /* debug error trap generation */ | |
136 | #define DBG_MUL_NODE 0x4000LL | |
137 | #define DBGMULNODE(s) do { if (debug_bits & DBG_MUL_NODE) { s } } while (0) /* debug multinode, only VF for now */ | |
138 | /* | |
139 | * debug_bits values already reserved: | |
140 | * | |
141 | * 0x1 DBG_BASIC | |
142 | * 0x2 DBG_EL | |
143 | * 0x4 DBG_EL_MIN | |
144 | * 0x8 < not reserved > | |
145 | * ... | |
146 | * 0x40 < not reserved > | |
147 | * 0x80 DBG_EPM | |
148 | * 0x100 < not reserved > | |
149 | * ... | |
150 | * 0x2000 < not reserved > | |
151 | * 0x4000 DBG_MUL_NODE | |
152 | * 0x8000 DBG_HCALL | |
153 | * 0x10000 DBG_PIC | |
154 | * 0x20000 DBG_EXCEPT | |
155 | * 0x40000 DBG_HPSTATE | |
156 | * 0x80000 DBG_MMU | |
157 | * 0x100000 DBG_MISS | |
158 | * 0x200000 DBG_MC | |
159 | * 0x400000 DBG_TS | |
160 | * 0x800000 DBG_ERR | |
161 | * 0x1000000 DBG_SSI | |
162 | * 0x2000000 DBG_LE | |
163 | * 0x4000000 DBG_ALIGN | |
164 | * 0x8000000 DBG_MONDO | |
165 | * 0x10000000 DBG_SOFTINT | |
166 | * 0x20000000 DBG_TICK | |
167 | * 0x40000000 DBG_DECODE | |
168 | * 0x80000000 DBG_DEV | |
169 | * 0x100000000 DBG_EXEC_LOOP | |
170 | * 0x200000000 DBG_ERR_TRAP | |
171 | * 0x1000000000 DBG_FSR | |
172 | * 0x2000000000 DBG_FPRS | |
173 | * 0x4000000000 DBG_TICK_READ | |
174 | * 0x8000000000 DBG_DAE | |
175 | * 0x10000000000 DBG_SCRATCH | |
176 | * 0x20000000000 DBG_XCACHE | |
177 | * 0x40000000000 DBG_FP | |
178 | * 0x80000000000 DBG_TM | |
179 | * 0x100000000000 DBG_CMP | |
180 | */ | |
181 | #else /* } { */ | |
182 | #define DBGCMP(_s) do { } while (0) | |
183 | #define DBGTM(_s) do { } while (0) | |
184 | #define DBGSCRATCH(_s) do { } while (0) | |
185 | #define DBGDAE(_s) do { } while (0) | |
186 | #define DBGLE(_s) do { } while (0) /* debug little endian */ | |
187 | #define DBGPIC(s) do { } while (0) /* debug Perf Cntrs */ | |
188 | #define DBGSOFTINT(s) do { } while (0) | |
189 | #define DBGTICK(s) do { } while (0) | |
190 | #define DBGTICKREAD(s) do { } while (0) | |
191 | #define DBGEPM(_s) do { } while (0) | |
192 | #define DBGALIGN(_s) do { } while (0) | |
193 | #define DBGHC(s) do { } while (0) /* debug exceptions */ | |
194 | #define DBGE(s) do { } while (0) /* debug exceptions */ | |
195 | #define DBGHPS(s) do { } while (0) /* debug exceptions */ | |
196 | #define DBGMMU(s) do { } while (0) /* debug exceptions */ | |
197 | #define DBGMISS(s) do { } while (0) /* debug exceptions */ | |
198 | #define DBGMC(s) do { } while (0) /* debug dram controllers */ | |
199 | #define DBGERR(s) do { } while (0) /* debug error injection */ | |
200 | #define DBGTSTACK(s) do { } while (0) /* debug TSTATE etc. */ | |
201 | #define DBGSSI(s) do { } while (0) /* debug SSI interrupts */ | |
202 | #define DBGMONDO(s) do { } while (0) /* debug mondo interrupts */ | |
203 | #define DBGERRTRAP(s) do { } while (0) /* debug error trap generation */ | |
204 | #define DBGMULNODE(s) do { } while (0) /* debug multinode, only VF for now */ | |
205 | #endif /* } */ | |
206 | ||
207 | typedef enum { | |
208 | TFlag_Not_Poss, TFlag_Priv, TFlag_HypPriv | |
209 | } tflag_t; | |
210 | ||
211 | #define T( _name ) SS_trap_##_name, #_name /* SunSPARC standard trap naming convention */ | |
212 | #define TN1( _name ) N1_trap_##_name, #_name /* Niagara1 specific trap naming convention */ | |
213 | #define TN2( _name ) N2_trap_##_name, #_name /* Niagara2 standard trap naming convention */ | |
214 | #define TRK( _name ) RK_trap_##_name, #_name /* Rock standard trap naming convention */ | |
215 | #define X TFlag_Not_Poss /* Cant be generated by HW - SW emulated only */ | |
216 | #define SW TFlag_Not_Poss /* Cant be generated by HW - SW emulated only */ | |
217 | #define P TFlag_Priv | |
218 | #define H TFlag_HypPriv | |
219 | #define UH TFlag_HypPriv /* legal, but unexpected by hypervisor (supervisor error) */ | |
220 | ||
221 | #define Pri(_maj, _min) (((_maj)<<16)|(_min)) | |
222 | ||
223 | #define E( _name ) _name, #_name /* Error naming convention */ | |
224 | #define B( _name, _i ) #_name, ((uint64_t)1 << _i) /* Error field name, bit position in CERER */ | |
225 | ||
226 | /* | |
227 | * macros used for determing the fields of sun4v TTE format | |
228 | */ | |
229 | #define SUN4V_TTED_V_BIT 63 | |
230 | #define SUN4V_TTED_V(n) (uint_t)((uint64_t)n >> SUN4V_TTED_V_BIT) | |
231 | #define SUN4V_TTED_NFO(n) (uint_t)(((uint64_t)n >> 62) & 0x1) | |
232 | #define SUN4V_TTED_IE(n) (uint_t)(((uint64_t)n >> 12) & 0x1) | |
233 | #define SUN4V_TTED_E(n) (uint_t)(((uint64_t)n >> 11) & 0x1) | |
234 | #define SUN4V_TTED_CP(n) (uint_t)(((uint64_t)n >> 10) & 0x1) | |
235 | #define SUN4V_TTED_CV(n) (uint_t)(((uint64_t)n >> 9) & 0x1) | |
236 | #define SUN4V_TTED_P(n) (uint_t)(((uint64_t)n >> 8) & 0x1) | |
237 | #define SUN4V_TTED_EP(n) (uint_t)(((uint64_t)n >> 7) & 0x1) | |
238 | #define SUN4V_TTED_X(n) SUN4V_TTED_EP(n) | |
239 | #define SUN4V_TTED_W(n) (uint_t)(((uint64_t)n >> 6) & 0x1) | |
240 | #define SUN4V_TTED_PS(n) (uint_t)((uint64_t)n & MASK64(3, 0)) | |
241 | #define SUN4V_TTET_VA(n) ((uint64_t)n & MASK64(41, 0)) | |
242 | ||
243 | #define SUN4V_TTE_ENTRY_SIZE 16 | |
244 | ||
245 | /* Use global array for this calculation */ | |
246 | extern uint8_t ss_page_size_shift[]; | |
247 | #define SUN4V_PAGE_SIZE_SHIFT(ps) ((uint_t)(ss_page_size_shift[(ps)])) | |
248 | ||
249 | /* | |
250 | * SunSPARC CPU core structures and typedefs | |
251 | */ | |
252 | ||
253 | /* | |
254 | * Common set of strand core identification fields for use in SS_STRAND | |
255 | * structures: | |
256 | * core: core number | |
257 | * vthread: thread number within the core | |
258 | * vcore_id: the thread number within the chip | |
259 | */ | |
260 | #define SS_CORE_NUM_FIELDS \ | |
261 | uint_t core; \ | |
262 | uint_t vthread; \ | |
263 | uint64_t vcore_id; | |
264 | ||
265 | ||
266 | /* SSR => Strand Specific Registers */ | |
267 | typedef enum { | |
268 | SSR_ScratchPad0 = 0, | |
269 | SSR_ScratchPad1, | |
270 | SSR_ScratchPad2, | |
271 | SSR_ScratchPad3, | |
272 | SSR_ScratchPad4, /* hypervisor only (Niagara) */ | |
273 | SSR_ScratchPad5, /* hypervisor only (Niagara) */ | |
274 | SSR_ScratchPad6, | |
275 | SSR_ScratchPad7, | |
276 | ||
277 | #ifdef ROCK | |
278 | /* Hypervisor Scratchpad Registers (0x00 to 0x18) */ | |
279 | SSR_ScratchPad8, | |
280 | SSR_ScratchPad9, | |
281 | SSR_ScratchPad10, | |
282 | SSR_ScratchPad11, | |
283 | #endif | |
284 | ||
285 | SSR_Num_Regs | |
286 | } ss_strand_regs_t; | |
287 | ||
288 | typedef struct SS_TLB ss_tlb_t; | |
289 | ||
290 | typedef struct NA_QUEUE { | |
291 | uint16_t head, tail; | |
292 | } na_queue_t; | |
293 | ||
294 | ||
295 | typedef struct SS_MMU ss_mmu_t; | |
296 | typedef struct SS_ERROR ss_error_t; | |
297 | ||
298 | /* Numbers for the SunSPARC strand interrupt queues */ | |
299 | typedef enum { | |
300 | NA_Q_mondo = 0, | |
301 | NA_Q_device = 1, | |
302 | NA_Q_resumable = 2, | |
303 | NA_Q_unresumable = 3 | |
304 | } na_qnum_t; | |
305 | ||
306 | typedef struct SS_L1_CACHE { | |
307 | RW_lock_t rwlock; | |
308 | uint64_t * tagp; | |
309 | uint64_t * datap; | |
310 | uint64_t bist_ctl; /* asi 0x42 va 0x00 ASI_SPARC_BIST_CTL_REG */ | |
311 | uint64_t inst_mask; /* asi 0x42 va 0x08 ASI_INST_MASK_REG */ | |
312 | bool_t assocdis; /* asi 0x42 va 0x10 ASI_LSU_DIAG_REG */ | |
313 | } ss_l1_cache_t; | |
314 | ||
315 | #define BIT(i) ((uint64_t)1<<i) | |
316 | #define BIT_TEST(_val, _bit) (((_val)>>(_bit)) & 0x1) | |
317 | ||
318 | /* | |
319 | * Context Type Encoding defined by SunSPARC | |
320 | * | |
321 | * N.B. These values are used as defined in the Rock DFSR | |
322 | * so they cannot be changed to arbitrary values other than | |
323 | * the ones listed below. | |
324 | */ | |
325 | typedef enum { | |
326 | ss_ctx_primary = 0, | |
327 | ss_ctx_secondary = 1, | |
328 | ss_ctx_nucleus = 2, | |
329 | ss_ctx_reserved = 3 | |
330 | } ss_ctx_t; | |
331 | ||
332 | ||
333 | #if defined(NIAGARA1) || defined(NIAGARA2) /* { */ | |
334 | ||
335 | /* Sparc Error Address Register Fields */ | |
336 | #define I_SYND(val) ((val & 0xff) << 16) | |
337 | #define I_REG_WIN(val) ((val & 0x3) << 9) | |
338 | #define I_REG_NUM(val) ((val & 0x1f) << 4) | |
339 | #define F_REG_NUM(val) ((val & 0x3f) << 4) | |
340 | #define EVEN_SYND(val) ((val & 0x7f) << 24) | |
341 | #define ODD_SYND(val) ((val & 0x7f) << 16) | |
342 | #define TLB_INDEX(val) ((val & 0x3f) << 4) | |
343 | #define MMU_PC(val) (val & 0xfffffffffff0) /* PC:47-4 Rsvd:3-0 */ | |
344 | #define MMU_VA(val) (val & 0xfffffffffff0) /* VA:47-4 Rsvd:3-0 */ | |
345 | #define L1_PA(val) (val & 0xfffffffff0) /* PA:39-4 Rsvd:3-0 */ | |
346 | ||
347 | /* ECC Codes section in Appendix A of PRM 1.2 */ | |
348 | ||
349 | #define IREG_FAKE_SYND_SINGLE 0x83 /* single bit error on data bit 0 */ | |
350 | #define IREG_FAKE_SYND_DOUBLE 0x73 /* uncorrectable double bit error */ | |
351 | #define FREG_FAKE_SYND_SINGLE 0x43 /* single bit error on bit 0 */ | |
352 | #define FREG_FAKE_SYND_DOUBLE 0x33 /* uncorrectible double bit error */ | |
353 | ||
354 | /* | |
355 | * Bitfield definitions for the LSU_CONTROL register | |
356 | */ | |
357 | ||
358 | #if defined(NIAGARA1) /* { */ | |
359 | #define LSU_CTRL_WATCH_VM MASK64(32,25) | |
360 | #define LSU_CTRL_WATCH_VR MASK64(22,22) | |
361 | #define LSU_CTRL_WATCH_VW MASK64(21,21) | |
362 | #endif /* } */ | |
363 | #if defined(NIAGARA2) /* { */ | |
364 | #define LSU_CTRL_WATCH_MODE MASK64(34,33) | |
365 | #define LSU_CTRL_WATCH_BM MASK64(32,25) | |
366 | #define LSU_CTRL_WATCH_RE MASK64(24,24) | |
367 | #define LSU_CTRL_WATCH_WE MASK64(23,23) | |
368 | #define LSU_CTRL_SPEC_EN MASK64(4,4) | |
369 | #endif /* } */ | |
370 | #define LSU_CTRL_DMMU_EN MASK64(3,3) | |
371 | #define LSU_CTRL_IMMU_EN MASK64(2,2) | |
372 | #define LSU_CTRL_DC_EN MASK64(1,1) | |
373 | #define LSU_CTRL_IC_EN MASK64(0,0) | |
374 | ||
375 | #if defined(NIAGARA1) /* { */ | |
376 | #define LSU_CTRL_REG_MASK (LSU_CTRL_WATCH_VM | LSU_CTRL_WATCH_VR | \ | |
377 | LSU_CTRL_WATCH_VW | LSU_CTRL_DMMU_EN | \ | |
378 | LSU_CTRL_IMMU_EN | LSU_CTRL_DC_EN | \ | |
379 | LSU_CTRL_IC_EN) | |
380 | #endif /* } */ | |
381 | #if defined(NIAGARA2) /* { */ | |
382 | #define LSU_CTRL_REG_MASK (LSU_CTRL_WATCH_MODE | LSU_CTRL_WATCH_BM | \ | |
383 | LSU_CTRL_WATCH_RE | LSU_CTRL_WATCH_WE | \ | |
384 | LSU_CTRL_SPEC_EN | LSU_CTRL_DMMU_EN | \ | |
385 | LSU_CTRL_IMMU_EN | LSU_CTRL_DC_EN | \ | |
386 | LSU_CTRL_IC_EN) | |
387 | #endif /* } */ | |
388 | ||
389 | #define LSU_CTRL_INITVAL (0LL) | |
390 | ||
391 | #endif /* } */ | |
392 | ||
393 | ||
394 | ||
395 | ||
396 | /* | |
397 | * Functions and definitions for TLB and MMU code | |
398 | */ | |
399 | ||
400 | ||
401 | /* FIXME: | |
402 | * This macro is a place holder for the correct register setup | |
403 | * that is required in order to be able to deliver a particular | |
404 | * fault resulting from a memory reference. | |
405 | */ | |
406 | #define MEMORY_ACCESS_TRAP() do { } while (0) | |
407 | ||
408 | ||
409 | /* | |
410 | * SunSPARC CPU TLB structures | |
411 | */ | |
412 | ||
413 | /* | |
414 | * Each hash table is divided into buckets, based on pfn, context and partid | |
415 | * The chains attached to a bucket are designed to have multiple readers and | |
416 | * only a single writer/modifier at any one time. | |
417 | * | |
418 | * FIXME: However, operations like entry probling and invalidate all etc. don't | |
419 | * use the hash ... | |
420 | * ... I'm going to assume that TLB contention between strands is sufficiently | |
421 | * low that we can get away with a single rw lock for the entire TLB. | |
422 | * This should be enough to get something working - we'll fix the performance | |
423 | * later when we get a chance to profile the running code .... | |
424 | * | |
425 | * Naturally, if we don't share TLBs between strand threads then there is no | |
426 | * need for any locks. | |
427 | * | |
428 | * Otherwise we have to implement a fair multiple-reader, single writer locking | |
429 | * scheme, that is hopefully fast - ish. | |
430 | * | |
431 | * FIXME: we use Solaris' reader/writer locks to get this working, but I suspect | |
432 | * they are tediously slow - quick measurement indicates they take around 400 instructions | |
433 | * to take and release an uncontested lock !! Need to profile this code and see if this is | |
434 | * a performance bottleneck. But for now this is sufficient to get this working. | |
435 | * | |
436 | * NOTE: if this is very low contention, we should probably simply move to a mutex | |
437 | * per bucket, since the performance of Solaris' mutexes is about twice that of the rwlock. | |
438 | * Increasing the number of buckets and better hashing alg would also reduce contention. | |
439 | * | |
440 | */ | |
441 | #ifdef ROCK /* { */ | |
442 | typedef uint32_t matchcontext_t; | |
443 | #else /* } { */ | |
444 | typedef uint16_t matchcontext_t; | |
445 | #endif /* } */ | |
446 | #define INVALID_PFN -1LL | |
447 | #define SS_TLB_REAL_CONTEXT ((matchcontext_t)-1) | |
448 | #define SS_TLB_INVALID_CONTEXT ((matchcontext_t)-2) | |
449 | #define SS_TLB_INVALID_PARTID ((uint16_t)-1) | |
450 | ||
451 | #define SS_NUCLEUS_CONTEXT 0 | |
452 | ||
453 | typedef struct TLB_ENTRY tlb_entry_t; | |
454 | ||
455 | typedef enum { | |
456 | SS_TLB_FLAG_READ = 0x001, /* niagara doesn't have read bit */ | |
457 | SS_TLB_FLAG_WRITE = 0x002, /* writeable */ | |
458 | SS_TLB_FLAG_EXEC = 0x004, /* executable */ | |
459 | SS_TLB_FLAG_PRIV = 0x008, /* privileged */ | |
460 | SS_TLB_FLAG_CP = 0x010, /* cachable in physically-indexed cache */ | |
461 | SS_TLB_FLAG_E = 0x020, /* side-effect */ | |
462 | SS_TLB_FLAG_NFO = 0x040, /* no-fault-only */ | |
463 | SS_TLB_FLAG_IE = 0x080, /* Invert Endian */ | |
464 | SS_TLB_FLAG_V = 0x100, /* valid */ | |
465 | SS_TLB_FLAG_LOCKED = 0x200 /* locked */ | |
466 | } tlb_flags_t; | |
467 | ||
468 | struct TLB_ENTRY { | |
469 | uint64_t tag_pfn; | |
470 | uint64_t pa_offset; /* (i.e. pa-va) */ | |
471 | uint64_t data; /* as returned by the data register read */ | |
472 | uint8_t match_shift; | |
473 | bool_t is_real; /* true for RA to PA, false for VA to PA translation */ | |
474 | tlb_flags_t flags; | |
475 | uint16_t tag_context; /* context value in TLB entry tag field */ | |
476 | matchcontext_t match_context; /* context used when matching entries; 0..12 bits */ | |
477 | /* -1 if this is a real translation not a virtual one */ | |
478 | /* -2 if this is not a valid translation */ | |
479 | uint16_t partid; | |
480 | sint16_t hashidx; /* used to help find the entry in the hash for unhooking */ | |
481 | /* == -1 if the entry is on the free list */ | |
482 | tlb_entry_t * nextp; | |
483 | }; | |
484 | ||
485 | /* | |
486 | * Niagara max page size is 256MB .. this value is used for | |
487 | * the TLB hashing index value | |
488 | */ | |
489 | ||
490 | #define SS_MAX_PAGE_SIZE_BITS 28 | |
491 | ||
492 | #if defined(NIAGARA1) || defined(NIAGARA2) /* { */ | |
493 | /* | |
494 | * Niagara VA hole | |
495 | */ | |
496 | #define SS_VA_HOLE_LB 0x0000800000000000 | |
497 | #define SS_VA_HOLE_UB 0xffff7fffffffffff | |
498 | /* Extend 48 bit VA to 64 bits */ | |
499 | #define VA48(_va) (((int64_t)(_va) << 16) >> 16) | |
500 | #define VA48_WARNING(_sp, _va) do {\ | |
501 | if ((_va) != VA48(_va))\ | |
502 | EXEC_WARNING(("@pc=0x%llx not a 48-bit VA 0x%llx",\ | |
503 | sp->pc, (_va)));\ | |
504 | } while (0) | |
505 | #define VA48_ASSERT(_va) ASSERT((_va) == VA48(_va)) | |
506 | #endif /* } */ | |
507 | ||
508 | typedef struct { | |
509 | tlb_entry_t * ptr; | |
510 | } tlb_hash_bucket_t; | |
511 | ||
512 | /* | |
513 | * TLB organisation is independent of the | |
514 | * search hash - and is merely determined by the | |
515 | * behaviour of the insert / demap functions. | |
516 | */ | |
517 | ||
518 | #if defined(NIAGARA1) || defined(NIAGARA2) /* { */ | |
519 | #define SS_TLB_HASH_ENTRIES 32 /* modest number */ | |
520 | #endif /* } */ | |
521 | #ifdef ROCK /* { */ | |
522 | #define SS_TLB_HASH_ENTRIES 256 /* less modest number */ | |
523 | #endif /* } */ | |
524 | #define SS_TLB_HASH_MASK (SS_TLB_HASH_ENTRIES-1) | |
525 | /* define replacement policy when all entries are valid: */ | |
526 | #define SS_TLB_REPLACE_RROBIN 1 | |
527 | /* #define SS_TLB_REPLACE_RANDOM 1 */ | |
528 | ||
529 | struct SS_TLB { | |
530 | uint_t nentries; | |
531 | RW_lock_t rwlock; | |
532 | tlb_entry_t * freep; | |
533 | tlb_hash_bucket_t hash[SS_TLB_HASH_ENTRIES]; | |
534 | tlb_entry_t * tlb_entryp; | |
535 | bool_t parity; | |
536 | uint_t shares; | |
537 | #if SS_TLB_REPLACE_RROBIN /* { */ | |
538 | uint_t last_replaced; | |
539 | #endif /* } */ | |
540 | #ifdef ROCK /* { */ | |
541 | uint8_t *lru_array; | |
542 | #endif /* } */ | |
543 | }; | |
544 | ||
545 | ||
546 | ||
547 | typedef struct SS_TLB_SPEC { | |
548 | uint_t nentries; | |
549 | bool_t parity; | |
550 | } ss_tlb_spec_t; | |
551 | ||
552 | ||
553 | typedef struct ERROR_PROC { | |
554 | tvaddr_t ldac_addr; | |
555 | tvaddr_t ldau_addr; | |
556 | tvaddr_t dac_addr; | |
557 | tvaddr_t dau_addr; | |
558 | } error_proc_t; | |
559 | ||
560 | /* | |
561 | * SunSPARC CPU specific info about how a debugger instance is | |
562 | * attached ... handled as a hidden data type from the debugger, | |
563 | * but provides this module info on which strand etc. the debugger | |
564 | * is actually attached to. | |
565 | */ | |
566 | ||
567 | typedef struct { | |
568 | domain_t * domainp; | |
569 | config_proc_t * config_procp; | |
570 | ||
571 | uint_t core; | |
572 | uint_t strand; | |
573 | ||
574 | sparcv9_cpu_t* strandp; | |
575 | } ss_dbgr_t; | |
576 | ||
577 | typedef enum SS_DEMAP ss_demap_t; | |
578 | ||
579 | typedef enum { | |
580 | NA_mem_read, NA_mem_write, NA_mem_clear | |
581 | } dbgr_mem_op_t; | |
582 | ||
583 | /* | |
584 | * All memory ASIs bit3=1 if the ASI is Little Endian | |
585 | */ | |
586 | #define SS_ASI_LE_MASK (1 << 3) | |
587 | ||
588 | typedef enum { | |
589 | MF_Normal = 0x01, /* if normal access, else alternate address space being used */ | |
590 | MF_MMU_Bypass = 0x02, /* if this ld/st should bypass MMU translation */ | |
591 | MF_Has_Priv = 0x04, /* if access is from priv or hpriv mode */ | |
592 | MF_No_Fault = 0x08, /* No faulting load specified */ | |
593 | MF_IO_Access = 0x10, /* Not a cacheable access - e.g. REAL_IO */ | |
594 | MF_Blk_Init = 0x20, /* Block Initialize effect */ | |
595 | MF_Atomic_Access = 0x40, /* Atomic instruction access (including 128-bit atomic load) */ | |
596 | MF_TLB_Real_Ctx = 0x80, /* Search TLB RA->PA mapping (due to ASI_*_real_* access) */ | |
597 | MF_Little_Endian = 0x100 | |
598 | } mem_flags_t; | |
599 | ||
600 | #if ERROR_INJECTION | |
601 | ||
602 | typedef enum { | |
603 | IFETCH = 0x01, | |
604 | LD = 0x02, | |
605 | ASI_LD = 0x04, | |
606 | ST = 0x08, | |
607 | ANY_OP = 0xff | |
608 | } error_op_t; | |
609 | ||
610 | typedef uint64_t error_type_t; | |
611 | ||
612 | #define ss_set_errcheck(npp) do { \ | |
613 | npp->error_check = npp->errorp->ldac_addr | \ | |
614 | npp->errorp->ldau_addr | npp->errorp->dac_addr | \ | |
615 | npp->errorp->dau_addr; \ | |
616 | } while (0) | |
617 | ||
618 | #endif /* ERROR_INJECTION */ | |
619 | ||
620 | /* The processor specific structure. */ | |
621 | typedef struct SS_PROC ss_proc_t; | |
622 | ||
623 | /* | |
624 | * functions defined outside the CPU loadable modules | |
625 | */ | |
626 | extern void host_atomic_get128be(uint64_t *, uint64_t *, uint64_t *); | |
627 | ||
628 | /* | |
629 | * extern definitions used by more than one libsunsparc source file | |
630 | */ | |
631 | extern void ss_parse(domain_t*, config_proc_t*); | |
632 | extern void ss_parse_tlb(ss_tlb_spec_t *); | |
633 | extern void ss_init(domain_t*, config_proc_t*); | |
634 | extern void ss_dump(domain_t*, config_proc_t*); | |
635 | extern bool_t ss_dbgr_regread(void*, uint_t, uint64_t*); | |
636 | extern bool_t ss_dbgr_regwrite(void*, uint_t, uint64_t); | |
637 | extern void ss_exec_setup(simcpu_t*); | |
638 | extern void ss_exec_cleanup(simcpu_t*); | |
639 | extern bool_t ss_save_state(simcpu_t*); | |
640 | extern void ss_check_async_event(simcpu_t*); | |
641 | extern void ss_take_exception(simcpu_t*); | |
642 | extern void ss_dump_tlbs(config_proc_t*, bool_t); | |
643 | extern void ss_dump_tlbs_nolock(config_proc_t*, bool_t); | |
644 | extern void ss_dump_instruction_counts(config_proc_t*); | |
645 | extern uint64_t ss_ext_signal(config_proc_t*, ext_sig_t, void*); | |
646 | extern bool_t ss_dev_mem_access(config_proc_t *config_procp, tpaddr_t addr, | |
647 | uint8_t *datap, uint64_t size, dev_access_t type); | |
648 | extern void * ss_dbgr_attach(domain_t*, config_proc_t*, char*); | |
649 | extern void ss_dbgr_detach(void*); | |
650 | extern uint64_t ss_dbgr_mem_read(void*, tvaddr_t, bool_t, uint8_t*, uint64_t); | |
651 | extern uint64_t ss_dbgr_mem_write(void*, tvaddr_t, bool_t, uint8_t*, uint64_t); | |
652 | extern uint64_t ss_dbgr_mem_clear(void*, tvaddr_t, bool_t, uint64_t); | |
653 | extern void ss_dbgr_set_break(void*, tvaddr_t); | |
654 | extern void ss_dbgr_clear_break(void*, tvaddr_t); | |
655 | extern void ss_tlb_unhash(ss_tlb_t*, tlb_entry_t*); | |
656 | extern void ss_tlb_unfree(ss_tlb_t*, tlb_entry_t*); | |
657 | extern void ss_free_tlb_entry(ss_tlb_t*, tlb_entry_t*); | |
658 | extern void ss_tlb_scrub(simcpu_t *, ss_tlb_t*, bool_t); | |
659 | extern void ss_xic_miss(simcpu_t*, xicache_line_t*, tvaddr_t); | |
660 | extern bool_t ss_tm_chkpt(simcpu_t *, tvaddr_t); | |
661 | extern void ss_tm_commit(simcpu_t *); | |
662 | extern void ss_tm_fail(simcpu_t *, uint64_t); | |
663 | extern uint64_t ss_read_pstate(sparcv9_cpu_t *); | |
664 | ||
665 | #if ERROR_INJECTION | |
666 | extern error_conf_t * new_errconf(error_op_t, error_type_t); | |
667 | extern error_conf_t * find_errconf(simcpu_t*, error_op_t, error_type_t); | |
668 | extern bool_t remove_errconf(simcpu_t * sp, error_conf_t * rmep); | |
669 | extern void dump_errconf(error_conf_t*); | |
670 | extern void extract_error_type(error_conf_t * errorconfp); | |
671 | extern void update_errflags(simcpu_t * sp); | |
672 | extern void clear_errflags(simcpu_t * sp); | |
673 | extern void ss_error_condition(simcpu_t*, error_conf_t*); | |
674 | extern void tlb_entry_error_match(simcpu_t*, ss_mmu_t*, tlb_entry_t*); | |
675 | #endif /* ERROR_INJECTION */ | |
676 | #if !defined(NDEBUG) /* { */ | |
677 | extern void ss_tlb_contents(FILE*, ss_tlb_t*, bool_t); | |
678 | #endif /* } */ | |
679 | extern uint64_t ss_cpu_mem(domain_t *, void*, sparcv9_cpu_t*, dbgr_mem_op_t, tvaddr_t, bool_t, uint8_t*, uint_t); | |
680 | extern void ss_asi_access( simcpu_t*, maccess_t, uint_t, uint_t, uint64_t, uint64_t, asi_flag_t); | |
681 | extern bool_t ss_demap(simcpu_t*, ss_demap_t, ss_mmu_t*, ss_tlb_t*, uint_t, bool_t, uint_t, tvaddr_t); | |
682 | extern void ss_tlb_flush_shares(simcpu_t *, ss_tlb_t *, bool_t); | |
683 | extern uint64_t ss_read_tick(simcpu_t*); | |
684 | extern void ss_write_tick(simcpu_t*, uint64_t); | |
685 | extern uint64_t ss_read_stick(simcpu_t*); | |
686 | extern void ss_write_stick(simcpu_t*, uint64_t); | |
687 | extern void ss_recomp_tick_target(simcpu_t*); | |
688 | extern uint64_t ss_tick_cmpr_read(simcpu_t *, tick_compare_t *); | |
689 | extern void ss_tick_cmpr_write(simcpu_t *, tick_compare_t *, uint64_t); | |
690 | extern void ss_recomp_cycle_target(simcpu_t*); | |
691 | extern void ss_memory_asi_access(simcpu_t*, maccess_t, uint64_t*, mem_flags_t, uint_t, uint_t, uint_t, tvaddr_t, tvaddr_t); | |
692 | extern void ss_check_interrupts(simcpu_t*); | |
693 | extern uint8_t host_ldstub(uint8_t *, uint8_t, uint8_t); | |
694 | extern uint32_t host_cas32(uint32_t *, uint32_t, uint32_t); | |
695 | extern uint64_t host_cas64(uint64_t *, uint64_t, uint64_t); | |
696 | extern uint32_t host_swap(uint32_t *, uint32_t); | |
697 | extern void v9_set_fsr_lower(simcpu_t*, uint64_t); | |
698 | extern void v9_set_fsr(simcpu_t*, uint64_t); | |
699 | extern void v9_set_fsr_fp_op(simcpu_t*, uint64_t); | |
700 | extern uint64_t v9_get_fsr(simcpu_t*); | |
701 | ||
702 | extern void ss_change_exec_state(ss_proc_t *npp, uint64_t running_status); | |
703 | ||
704 | extern uint64_t xor_bits(uint64_t); | |
705 | ||
706 | uint_t ss_get_cpuid(simcpu_t *sp); | |
707 | void ss_trash_regs(sparcv9_cpu_t * v9p, uint64_t val); | |
708 | /* | |
709 | * CPU version macros | |
710 | */ | |
711 | #define SS_VER_MANUF_OFFSET 48 /* bits 63:48 */ | |
712 | #define SS_VER_IMPL_OFFSET 32 /* bits 47:32 */ | |
713 | #define SS_VER_MASK_OFFSET 24 /* bits 31:24 */ | |
714 | #define SS_VER_MAXGL_OFFSET 16 /* bits 18:16 */ | |
715 | #define SS_VER_MAXTL_OFFSET 8 /* bits 15:8:0 */ | |
716 | #define SS_VER_NWINS_OFFSET 0 /* bits 4:0 */ | |
717 | ||
718 | #define SS_MAKE_VER_UPPER40(manuf, impl, mask) \ | |
719 | ((manuf<<SS_VER_MANUF_OFFSET)| \ | |
720 | (impl<<SS_VER_IMPL_OFFSET)| \ | |
721 | (mask<<SS_VER_MASK_OFFSET)) | |
722 | ||
723 | #define SS_MAKE_VER_LOWER24(ngl, maxtl, nwins) \ | |
724 | (((ngl-1)<<SS_VER_MAXGL_OFFSET)| \ | |
725 | (maxtl<<SS_VER_MAXTL_OFFSET)| \ | |
726 | ((nwins-1)<<SS_VER_NWINS_OFFSET)) | |
727 | ||
728 | #define RSVD_MASK(_sp, mask, val, asi, addr) \ | |
729 | do { \ | |
730 | if ((val) & ~(mask)) { \ | |
731 | EXEC_WARNING(("pc=0x%llx : stxa 0x%llx, [0x%x]0x%x: " \ | |
732 | "Attempted store to rsvd fields being masked out", \ | |
733 | (_sp)->pc, (val), (addr), (asi))); \ | |
734 | (val) &= (mask); \ | |
735 | } \ | |
736 | } while (0) | |
737 | ||
738 | /* | |
739 | * Identical to above RSVD_MASK macro, but safe for use when _sp pointer may be NULL. | |
740 | * Should be kept in sync with the above macro for any changes. | |
741 | */ | |
742 | #define ROCK_RSVD_MASK(_sp, mask, val, asi, addr) \ | |
743 | do { \ | |
744 | if ((val) & ~(mask)) { \ | |
745 | if ((_sp) != NULL) { \ | |
746 | EXEC_WARNING(("pc=0x%llx : stxa 0x%llx, [0x%x]0x%x: " \ | |
747 | "Attempted store to rsvd fields being masked out", \ | |
748 | (_sp)->pc, (val), (addr), (asi))); \ | |
749 | } else { \ | |
750 | EXEC_WARNING(("System controller access : stxa 0x%llx, [0x%x]0x%x: " \ | |
751 | "Attempted store to rsvd fields being masked out", \ | |
752 | (val), (addr), (asi))); \ | |
753 | } \ | |
754 | (val) &= (mask); \ | |
755 | } \ | |
756 | } while (0) | |
757 | ||
758 | #ifdef __cplusplus | |
759 | } | |
760 | #endif | |
761 | ||
762 | #endif /* _SS_COMMON_H */ |