Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sunsparc / common / ss_common.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: ss_common.c
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#pragma ident "@(#)ss_common.c 1.257 07/10/12 SMI"
29
30 /*
31 * Complete the parsing of a SunSPARC processor.
32 *
33 * Pick out the relevent info and allocate the
34 * simcpu_t structures in the config_proc that
35 * gets handed to us.
36 */
37
38 /*
39 * This is where the definitions get complicated.
40 * There is a processor specific component, a generic processor
41 * family component, and then the simulator infrastructure component.
42 * The latter is basically glue to tie a processor to a domain, and
43 * the processor specific info. The family component is general
44 * (ish) e.g. a v9 processor .. with a bunch of data structures
45 * flags etc. only understood by the family code, and then there is
46 * abunch of code and data specific to this CPU.
47 * All of these items get parsed and configured as part of this code.
48 *
49 * Note that this file is compiled three times in order to create
50 * the three processor specific loadable modules: libniagara.so,
51 * libniagara2.so, and librock.so.
52 */
53
54#include <stdio.h>
55#include <stdlib.h>
56#include <unistd.h>
57#include <string.h> /* memcpy/memset */
58#include <strings.h>
59#include <thread.h>
60#include <sys/types.h>
61#include <sys/stat.h>
62#include <fcntl.h>
63#include <sys/mman.h>
64
65#include "ss_common.h"
66#include "magictraps.h"
67#include "save_restore.h"
68
69 /*
70 * The following chip specific header files contain #if ... #endif
71 * statements so we don't have to worry about including one chip's
72 * definitions in the compilation of another's.
73 */
74
75#ifdef NIAGARA1
76#include "niagara.h"
77#endif
78
79#ifdef NIAGARA2
80#include "niagara2.h"
81#endif
82
83#ifdef ROCK /* { */
84#include "rock.h"
85#endif /* } */
86
87#include "ss_hwtw.h"
88
89#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
90/* Need to define this as processor specific code somewhere */
91#define PIC_MAX UINT32_MAX
92
93 /*
94 * defines used for manipulating pcr and pic regs
95 *
96 * PIC1 PIC0
97 * [63------32][31------0]
98 */
99/* Return the appropriate pic value from within the 64bit counter */
100#define CPU_COUNTER_TO_PIC0(cntr) ((cntr) & 0xFFFFFFFFULL)
101#define CPU_COUNTER_TO_PIC1(cntr) ((cntr) >> 32)
102
103/* Update the 64bit counter with the appropriate pic value */
104#define PIC0_PIC1_TO_CPU_COUNTER(pic0, pic1) ((pic0) | (((uint64_t)(pic1)) << 32))
105#endif /* } */
106
107uint64_t* lookup_sim_addr(simcpu_t *sp, uint64_t *sim_addr);
108
109ss_trap_list_t ss_trap_list[0x200];
110
111#define DBGP(s) do { s } while (0)
112
113static void parse_debug_hook(ss_proc_t *procp);
114
115#ifdef HW_TABLEWALK
116static bool_t ss_hwtw_get_tte_entry(simcpu_t*, uint8_t *, uint64_t*);
117#endif /* HW_TABLEWALK */
118static void ss_tlb_init(ss_tlb_t * tlbp, uint_t nentries);
119static void ss_l1_cache_init(ss_l1_cache_t * cachep, uint32_t cachesize,
120 bool_t is_immu);
121
122 /*
123 * Global array for calculating page size shift bits
124 * The sun4v page size is 4 bits
125 */
126#if defined(ROCK)
127uint8_t ss_page_size_shift[16]={ 13, 16, 19, 22, 25, 28, 31, 34 };
128#elif defined(NIAGARA1) || defined(NIAGARA2)
129uint8_t ss_page_size_shift[16]={ 13, 16, 0, 22, 0, 28, 0, 0 };
130#else
131#error "No valid processor defined."
132#endif
133
134
135uint64_t ss_ext_signal(config_proc_t * config_procp, ext_sig_t sigtype,
136 void *vp);
137
138void * ss_dbgr_attach(domain_t *, config_proc_t *, char *);
139void ss_dbgr_detach(void *);
140
141bool_t ss_dbgr_regread(void*, uint_t, uint64_t *);
142bool_t ss_dbgr_regwrite(void*, uint_t, uint64_t);
143uint64_t ss_dbgr_mem_read(void*, tvaddr_t, bool_t, uint8_t *, uint64_t);
144uint64_t ss_dbgr_mem_write(void*, tvaddr_t, bool_t, uint8_t *, uint64_t);
145uint64_t ss_dbgr_mem_clear(void*, tvaddr_t, bool_t, uint64_t);
146void ss_dbgr_set_break(void*, tvaddr_t);
147void ss_dbgr_clear_break(void*, tvaddr_t);
148
149static ss_proc_t * ss_proc_alloc(config_proc_t *);
150
151
152 /* genuinely static functions */
153
154 /* VtoP tranlsation used by debugger interface */
155static bool_t ss_vtop_translate( ss_proc_t *, sparcv9_cpu_t * strandp, tvaddr_t va, tpaddr_t *pap, tvaddr_t * vlenp);
156
157static tpaddr_t ss_pmem_op(
158 domain_t * domainp,
159 ss_proc_t * procp,
160 sparcv9_cpu_t * strandp,
161 dbgr_mem_op_t memop,
162 tpaddr_t pa,
163 uint8_t * bufp,
164 tpaddr_t size );
165
166static void ss_xdc_miss(simcpu_t *, uint64_t * regp, tvaddr_t, maccess_t op);
167static void ss_read_state_reg(simcpu_t * sp, uint_t rdest, uint_t state_reg);
168static void ss_write_state_reg(simcpu_t * sp, uint_t state_reg, uint64_t val);
169static void ss_read_priv_reg(simcpu_t * sp, uint_t rdest, uint_t priv_reg);
170static void ss_write_priv_reg(simcpu_t * sp, uint_t priv_reg, uint64_t val);
171static void ss_read_hyp_priv_reg(simcpu_t * sp, uint_t rdest, uint_t priv_reg);
172static void ss_write_hyp_priv_reg(simcpu_t * sp, uint_t priv_reg, uint64_t val);
173
174static void ss_done_retry(simcpu_t * sp, bool_t);
175static void ss_jpriv(simcpu_t * sp, tvaddr_t);
176
177static void ss_post_precise_trap(simcpu_t *, sparcv9_trap_type_t);
178static void ss_reset_trap(simcpu_t * sp, ss_trap_type_t tt);
179
180static void ss_cycle_target_match(simcpu_t *);
181
182#define NA_HPSTATE_ENB_BIT 11 /* ENB bit in HPSTATE is bit 11 */
183
184#define V9_TSTATE_GL_MASK ((uint64_t)0x7)
185#define V9_TSTATE_GL_SHIFT 40
186#define V9_TSTATE_CCR_MASK ((uint64_t)0xff)
187#define V9_TSTATE_CCR_SHIFT 32
188#define V9_TSTATE_ASI_MASK ((uint64_t)0xff)
189#define V9_TSTATE_ASI_SHIFT 24
190#define V9_TSTATE_PSTATE_MASK ((uint64_t)0x7ff) /* FIXME */
191#define V9_TSTATE_PSTATE_SHIFT 8
192#define V9_TSTATE_CWP_MASK ((uint64_t)0x1f)
193#define V9_TSTATE_CWP_SHIFT 0
194
195#define V9_CCR_MASK (0xffLL)
196#define V9_ASI_MASK (0xffLL)
197#define V9_PIL_MASK (0xfLL)
198
199
200
201 /*
202 * Macros used everywhere that we change the processor state
203 * employ these to make sure that other variables that are defined by
204 * the cpu state are kept consistent
205 */
206
207#if 0 /* { */
208#define V9_PSTATE_CHANGED(_v9p)
209
210 /* the mmu_bypass flag for niagara depends whether we are in hpriv or red state or not */
211#define V9_HPSTATE_CHANGED(_sp, _v9p) do { \
212 ss_strand_t * _nsp; \
213 _nsp = _v9p->impl_specificp; \
214 \
215 _nsp->mmu_bypass = (_v9p->state == V9_HyperPriv) || (_v9p->state == V9_RED); \
216 DBGHPS( lprintf(_sp->gid, "hpstate = %s\n", sparcv9_state_name[ _v9p->state ]); ); \
217 } while (0)
218#endif /* } */
219
220#if ERROR_INJECTION
221#define SET_ERROR_CHECK(_sp) do { \
222 if (_sp->error_enabled) \
223 _sp->error_check = \
224 (_newstate == _sp->error_priv) ? true : false; \
225 } while (0)
226#else
227#define SET_ERROR_CHECK(_sp) do { } while (0)
228#endif
229
230#define V9_STATE_CHANGE(_isp, _iv9p, _inewstate) do { \
231 sparcv9_cpu_t * _v9p = (_iv9p); \
232 sparcv9_state_t _newstate = (_inewstate); \
233 ss_strand_t * _nsp; \
234 simcpu_t * _sp = _isp; \
235 \
236 PERF_ACCUMULATE_ICOUNT(_v9p); \
237 \
238 _nsp = _v9p->impl_specificp; \
239 _nsp->mmu_bypass = (V9_HyperPriv==_newstate) || (V9_RED==_newstate); \
240 DBGHPS( extern char * sparcv9_state_name[]; \
241 lprintf(_sp->gid, "hpstate = %s -> %s (pc=0x%llx)\n", sparcv9_state_name[ _v9p->state ], sparcv9_state_name[ _newstate ], _sp->pc); ); \
242 _v9p->state = (_newstate); \
243 xcache_set_tagstate(_sp); \
244 SET_ERROR_CHECK(_sp); \
245 \
246 } while (0)
247
248
249#define V9_PSTATE_AM_CHANGED(_v9p) do { \
250 } while (0)
251
252#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
253
254/*
255 * The simulated PIC register values are only updated when the new values
256 * are required. To do this, the count source for each counter is sampled
257 * after each update so a delta can be derived.
258 *
259 * The implementation is simplistic in that the count controls are ignored,
260 * but it is enough to test the Solaris PIC code.
261 */
262#define UPDATE_PIC( _sp, _nsp, _v9p ) do { \
263 uint64_t _new; \
264 _new = RAW_TICK(_v9p); \
265 (_nsp)->pic0 += (_new - (_nsp)->pic0_sample_base); \
266 (_nsp)->pic0_sample_base = _new; \
267 _new = ICOUNT(_sp); \
268 (_nsp)->pic1 += (ICOUNT(_sp) - (_nsp)->pic1_sample_base); \
269 (_nsp)->pic1_sample_base = _new; \
270 } while (0)
271
272#define RESET_PIC_SAMPLE_BASES( _sp, _nsp, _v9p ) do { \
273 (_nsp)->pic0_sample_base = RAW_TICK(_v9p); \
274 (_nsp)->pic1_sample_base = ICOUNT(_sp); \
275 } while (0)
276
277#endif /* } */
278
279ss_proc_t * ss_proc_alloc(config_proc_t * config_procp)
280{
281 ss_proc_t * procp;
282
283 procp = Xcalloc(1, ss_proc_t);
284 procp->config_procp = config_procp;
285 config_procp->procp = procp;
286
287 procp->rstv_addr = (tvaddr_t)0;
288 procp->has_fpu = true; /* FPU present by default */
289
290 procp->nglobals = SS_VER_MAXGL + 1;
291 procp->maxtl = SS_VER_MAXTL;
292 procp->nwins = SS_VER_MAXWIN + 1;
293
294 procp->itlbspec.nentries = DEFAULT_ITLB_ENTRIES; /* FIXME */
295 procp->itlbspec.parity = false;
296 procp->dtlbspec.nentries = DEFAULT_DTLB_ENTRIES;
297 procp->dtlbspec.parity = false;
298#if defined(ROCK)
299 procp->tlbspec.nentries = DEFAULT_TLB_ENTRIES; /* Rock has a unified L2 TLB also */
300 procp->tlbspec.parity = false;
301 /*
302 * Initialize the real page size info. As per the PRM, for real translations
303 * we probe the TLB 8 times (8 page sizes enabled) and use the following
304 * order: 256MB -> 2GB -> 16GB -> 8KB -> 64KB -> 512KB -> 4MB -> 32MB
305 */
306 procp->real_page_size.enabled_page_sizes = 8;
307
308 procp->real_page_size.page_size_shift[0] = PGSZCODE_TO_SHIFT(5);
309 procp->real_page_size.page_size_shift[1] = PGSZCODE_TO_SHIFT(6);
310 procp->real_page_size.page_size_shift[2] = PGSZCODE_TO_SHIFT(7);
311 procp->real_page_size.page_size_shift[3] = PGSZCODE_TO_SHIFT(0);
312 procp->real_page_size.page_size_shift[4] = PGSZCODE_TO_SHIFT(1);
313 procp->real_page_size.page_size_shift[5] = PGSZCODE_TO_SHIFT(2);
314 procp->real_page_size.page_size_shift[6] = PGSZCODE_TO_SHIFT(3);
315 procp->real_page_size.page_size_shift[7] = PGSZCODE_TO_SHIFT(4);
316
317 /* Initialize jrand48 randstate array to seed values */
318 procp->randstate[0] = RANDSEED1;
319 procp->randstate[1] = RANDSEED2;
320 procp->randstate[2] = RANDSEED3;
321
322 procp->axis_console = false;
323 procp->erratum66_monitor = false;
324 procp->no_stingray = false;
325
326#ifdef ROCK_FAKE_SP /* { */
327 /* For 'fake_sp', default chip id is based on conf file order. */
328 procp->fake_chip_id = procp->config_procp->domainp->systemp->fake_sp ?
329 config_procp->proc_id : 0;
330#endif /* } */
331#endif
332
333#if PERFORMANCE_CHECK
334 procp->proc_debug.perf_cycle_gap = PERF_CYCLE_GAP;
335 procp->proc_debug.exit_at = 0x0ULL;
336#endif
337 return procp;
338}
339
340#if ERROR_INJECTION
341
342void extract_error_op(error_conf_t * errorconfp)
343{
344 errorconfp->op_namep = strdup(lex.strp);
345
346 if (streq(lex.strp,"ifetch"))
347 errorconfp->op = IFETCH;
348 else if (streq(lex.strp,"ld"))
349 errorconfp->op = LD;
350 else if (streq(lex.strp,"asi_ld"))
351 errorconfp->op = ASI_LD;
352 else if (streq(lex.strp,"st"))
353 errorconfp->op = ST;
354 else if (streq(lex.strp,"any"))
355 errorconfp->op = ANY_OP;
356 else
357 lex_fatal("unknown error type parsing error config");
358}
359
360void extract_error_priv(error_conf_t * errorconfp)
361{
362 errorconfp->priv_namep = strdup(lex.strp);
363
364 if (streq(lex.strp,"hyper"))
365 errorconfp->priv = V9_HyperPriv;
366 else if (streq(lex.strp,"priv"))
367 errorconfp->priv = V9_Priv;
368 else if (streq(lex.strp,"user"))
369 errorconfp->priv = V9_User;
370 else if (streq(lex.strp,"red"))
371 errorconfp->priv = V9_RED;
372 else
373 lex_fatal("unknown error type parsing error config");
374}
375
376void dump_errconf(error_conf_t * ep) {
377 uint_t count = 1;
378
379 while (ep != NULL) {
380 lprintf(-1, "Error Config #%u\n",count);
381 lprintf(-1, " cycle: %llu\n",ep->cycle);
382 lprintf(-1, " type: %s\n",ep->type_namep);
383 lprintf(-1, " op: %s\n",ep->op_namep);
384 lprintf(-1, " priv: %s\n",ep->priv_namep);
385 ep = ep->nextp;
386 count++;
387 }
388}
389
390void parse_error(domain_t * domainp)
391{
392 error_conf_t **pep, *ep, *errorconfp;
393
394 errorconfp = Xmalloc( sizeof(error_conf_t) );
395 errorconfp->cycle = ~0ull;
396 errorconfp->priv = V9_HyperPriv;
397 errorconfp->type = NULL;
398 errorconfp->op = NULL;
399 errorconfp->npp = NULL;
400
401 lex_get(T_L_Brace);
402
403 do {
404 lexer_tok_t tok;
405
406 tok = lex_get_token();
407
408 if (tok == T_EOF)
409 lex_fatal("unexpected end of file parsing cpu");
410 if (tok == T_R_Brace) break;
411 if (tok != T_Token)
412 lex_fatal("token expected in SunSPARC processor specification");
413
414 if (streq(lex.strp,"cycle")) {
415 errorconfp->cycle = parse_number_assign();
416 } else
417 if (streq(lex.strp,"type")) {
418 lex_get(T_String);
419 extract_error_type(errorconfp);
420 lex_get(T_S_Colon);
421 } else
422 if (streq(lex.strp,"op")) {
423 lex_get(T_String);
424 extract_error_op(errorconfp);
425 lex_get(T_S_Colon);
426 } else
427 if (streq(lex.strp,"priv")) {
428 lex_get(T_String);
429 extract_error_priv(errorconfp);
430 lex_get(T_S_Colon);
431 } else
432 lex_fatal("unknown token %s in error specification",
433 lex.strp);
434 } while (1);
435
436 /* insert error_conf_t into list sorted by cycle */
437 for (pep = &(domainp->errlistp); (ep=*pep) != NULL; pep =&(ep->nextp) ) {
438 if (errorconfp->cycle < ep->cycle) break;
439 }
440
441 errorconfp->nextp = *pep;
442 *pep = errorconfp;
443
444 lex_unget();
445
446 lex_get(T_R_Brace);
447}
448
449error_conf_t * new_errconf(error_op_t op, error_type_t type) {
450 error_conf_t * ep;
451
452 ep = Xcalloc(1, error_conf_t);
453 ep->op = op;
454 ep->type = type;
455 ep->op_namep = strdup("unknown");
456 ep->type_namep = ep->op_namep;
457 ep->priv_namep = ep->op_namep;
458 return ep;
459}
460
461error_conf_t * find_errconf(simcpu_t * sp, error_op_t op, error_type_t type) {
462 error_conf_t * ep;
463
464 ep = sp->errorp->errlistp;
465
466 while (ep != NULL) {
467 if ((ep->op & op) && (ep->type & type)) break;
468 ep = ep->nextp;
469 }
470
471 return ep;
472}
473
474 /*
475 * remove error config from the list of current errors
476 * return NULL if no more errors in current error list although there may
477 * still be more in the processor pending error list waiting for a cycle match
478 */
479
480bool_t remove_errconf(simcpu_t * sp, error_conf_t * rmep) {
481 error_conf_t ** pep, * ep;
482
483 for (pep = &(sp->errorp->errlistp); (ep=*pep) != NULL; pep =&(ep->nextp)) {
484 if (ep == rmep) break;
485 }
486 *pep = ep->nextp;
487 Xfree(rmep);
488
489 return (sp->errorp->errlistp ? true : false);
490}
491
492void clear_errflags(simcpu_t * sp) {
493 sp->error_enabled = false;
494 sp->error_check = false;
495 sp->errorp->check_xicache = false;
496 sp->errorp->check_xdcache = false;
497 sp->errorp->check_dtlb = false;
498}
499#endif /* ERROR_INJECTION */
500
501 /*
502 * Complete the creation and parsing of this specific cpu
503 *
504 * .. basically parse and allocate what is necessary.
505 */
506
507void ss_parse(domain_t * domainp, config_proc_t * config_procp)
508{
509 ss_proc_t *procp;
510 lexer_tok_t tok;
511 char buf[64];
512 config_dev_t *pd;
513 config_dev_t *overlapp;
514 config_addr_t *ap;
515 bool_t debug_hook_defined = false;
516 uint64_t manuf = SS_VER_MANUF;
517 uint64_t impl = SS_VER_IMPL;
518 uint64_t mask = SS_VER_MASK;
519 uint_t nvthreads = 0, ncores = 0;
520 uint64_t core_mask = 0;
521
522 sprintf(buf, "cpu-%02d", config_procp->proc_id);
523DBG( lprintf(-1, "SunSPARC: parsing cpu %s\n", buf); );
524
525 /*
526 * fill in with default values where necessary
527 */
528
529 procp = ss_proc_alloc(config_procp);
530
531 do {
532 tok = lex_get_token();
533
534 if (tok == T_EOF) lex_fatal("unexpected end of file parsing cpu");
535 if (tok == T_R_Brace) break;
536 if (tok != T_Token) lex_fatal("token expected in SunSPARC processor specification");
537
538 if (streq(lex.strp,"rstv")) {
539 procp->rstv_addr = parse_number_assign();
540 if ((procp->rstv_addr & 31) != 0) lex_fatal("SunSPARC CPU RSTV addr needs to be 32byte aligned");
541 } else
542 if (streq(lex.strp,"maxtl")) {
543 procp->maxtl = parse_number_assign();
544 if (procp->maxtl >= SPARCv9_TLSPACE) fatal("Sorry maxtl must be %u or less (recompile sim for more)", SPARCv9_TLSPACE-1);
545 } else
546 if (streq(lex.strp,"ver")) {
547 tok = lex_get_token();
548 if (tok == T_Number) {
549 lex_unget();
550 procp->ver = parse_number_assign() &
551 (0xFFFFFFFFFFULL<<SS_VER_MASK_OFFSET);
552 } else
553 if (tok == T_String) {
554 while (tok != T_S_Colon) {
555 if (streq(lex.strp,"mask")) {
556 lex_get(T_Number);
557 mask = lex.val;
558 } else
559 if (streq(lex.strp,"impl")) {
560 lex_get(T_Number);
561 impl = lex.val;
562 } else
563 if (streq(lex.strp,"manuf")) {
564 lex_get(T_Number);
565 manuf = lex.val;
566 } else {
567 printf("\nUnknown ver option %s\n", lex.strp);
568 }
569 tok = lex_get_token();
570 }
571 }
572 } else
573 if (streq(lex.strp,"clkfreq")) {
574 procp->clkfreq = parse_number_assign();
575 } else
576 if (streq(lex.strp,"core_mask")) {
577 core_mask = parse_number_assign();
578 } else
579 if (streq(lex.strp,"cores")) {
580 ncores = parse_number_assign();
581 } else
582 if (streq(lex.strp, "vthreads") || streq(lex.strp, "strands")) {
583 nvthreads = parse_number_assign();
584 } else
585 if (streq(lex.strp,"nwins")) {
586 procp->nwins = parse_number_assign();
587 } else
588 if (streq(lex.strp,"nglobals")) {
589 procp->nglobals = parse_number_assign();
590 } else
591 if (streq(lex.strp,"itlb")) {
592 ss_parse_tlb(&procp->itlbspec);
593 } else
594 if (streq(lex.strp,"dtlb")) {
595 ss_parse_tlb(&procp->dtlbspec);
596 } else
597 if (streq(lex.strp,"nofpu")) {
598 procp->has_fpu = false;
599 lex_get(T_S_Colon);
600 } else
601#ifdef NIAGARA2
602 if (streq(lex.strp, "crypto_synchronous")) {
603 procp->crypto_synchronous = !!parse_number_assign();
604 } else
605#endif /* NIAGARA2 */
606
607#if ERROR_INJECTION /* { */
608 if (streq(lex.strp,"error")) {
609 parse_error(domainp);
610 } else
611#endif /* ERROR_INJECTION } */
612
613
614#if PERFORMANCE_CHECK /* { */
615 if (streq(lex.strp,"exit_at")) {
616 procp->proc_debug.exit_at = parse_number_assign();
617 } else
618
619 if (streq(lex.strp,"perf_cycle_gap")) {
620 procp->proc_debug.perf_cycle_gap = parse_number_assign();
621 } else
622#endif /* PERFORMANCE_CHECK } */
623
624 if (streq(lex.strp, "debug_hook")) {
625 if (debug_hook_defined)
626 lex_fatal("Cannot have more than one debug_hook definition in conf file");
627 else
628 debug_hook_defined = true;
629 parse_debug_hook(procp);
630 } else
631#if ERROR_TRAP_GEN /* { */
632 if (streq(lex.strp,"error_asi")) {
633 ss_error_asi_parse(procp, false);
634 } else
635 if (streq(lex.strp,"error_event")) {
636 ss_error_event_parse(procp, false);
637 } else
638 if (streq(lex.strp,"error_reload_file_name")) {
639 ss_error_parse_filename(procp);
640 } else
641#endif /* ERROR_TRAP_GEN } */
642 if (ss_parse_proc_entry(procp, domainp) == true) {
643 /* Handled processor specific token */
644 } else
645 lex_fatal("unknown token %s in cpu specification", lex.strp);
646 } while (1);
647
648 lex_unget(); /* put the r brace back for the caller ! FIXME */
649
650#if ERROR_INJECTION
651 dump_errconf(domainp->errlistp);
652#endif
653
654 /*
655 * Round out with values that didn't get set
656 * during parsing.
657 */
658
659 if (procp->clkfreq == 0) lex_fatal("clkfreq not specified in processor definition");
660 /* nvthreads and ncores are for backward compatibility */
661 if (core_mask == 0) {
662 if (ncores == 0 && nvthreads == 0 ) lex_fatal("core_mask not specified in processor definition");
663 if (ncores == 0) lex_fatal("ncores not specified in processor definition");
664 if (ncores > CORESPERCHIP) lex_fatal("ncores must be <= %d", CORESPERCHIP);
665 if (nvthreads == 0) lex_fatal("nvthreads not specified in processor definition");
666 if (nvthreads > STRANDSPERCORE) lex_fatal("nvthreads must be <= %d", STRANDSPERCORE);
667 core_mask = (1 << nvthreads) - 1;
668 for (ncores--; ncores > 0 ; ncores--)
669 core_mask |= core_mask << STRANDSPERCORE;
670 } else {
671 if (ncores != 0 || nvthreads != 0)
672 lex_fatal("nvthreads/ncores should not be present when using core_mask");
673 /* check for non-existant strands */
674 if ((core_mask & VALID_CORE_MASK) != core_mask)
675 lex_fatal("core_mask has bits for non-existant strands");
676 }
677 procp->core_mask = core_mask;
678 if (procp->nwins != (SS_VER_MAXWIN + 1))
679 warning("nwins set to non-standard value for this processor");
680 if (procp->maxtl != SS_VER_MAXTL)
681 warning("maxtl set to non-standard value for this processor");
682 if (procp->nglobals != (SS_VER_MAXGL + 1))
683 warning("nglobals set to non-standard value for this processor");
684 if (procp->ver == 0)
685 procp->ver = SS_MAKE_VER_UPPER40(manuf, impl, mask);
686
687 procp->ver |= SS_MAKE_VER_LOWER24(procp->nglobals, procp->maxtl,
688 procp->nwins);
689
690 /*
691 * So now we know we got a specific chip (Niagara or Rock for example) in the domain,
692 * we create the pseudo physical IO devices that this chip has for it's control registers.
693 * For things like the clock unit and memory controllers etc.
694 */
695 ss_setup_pseudo_devs(domainp, procp);
696}
697
698/*
699 * Parse a TLB description for either the
700 * I or D TLB for the proc.
701 */
702
703void ss_parse_tlb(ss_tlb_spec_t * tlbspecp)
704{
705 /* just swallow for the moment */
706 lex_get(T_L_Brace);
707 do {
708 lexer_tok_t tok;
709
710 tok = lex_get_token();
711
712 if (tok == T_EOF) lex_fatal("unexpected end of file parsing SunSPARC CPU tlb spec");
713 if (tok == T_R_Brace) break;
714 if (tok != T_Token) lex_fatal("token expected in SunSPARC processor tlb specification");
715
716 if (streq(lex.strp,"entries")) {
717 uint_t num;
718 num = (uint_t)parse_number_assign();
719 if (num<1) lex_fatal("TLB requires at least one entry");
720 if (num>4096) lex_fatal("More than 4096 entries is not allowed");
721
722 tlbspecp->nentries = num;
723 } else if (streq(lex.strp,"parity")) {
724 tlbspecp->parity = true;
725 lex_get(T_S_Colon);
726 } else
727 lex_fatal("unknown token %s in cpu TLB specification", lex.strp);
728 } while (1);
729}
730
731
732
733
734
735
736static bool_t
737ss_check_vahole(simcpu_t* sp, tvaddr_t pc)
738{
739#if /* defined(NIAGARA1) || */ defined(NIAGARA2) /* { */
740 if (VA48(pc) != pc) {
741 sparcv9_cpu_t * v9p;
742 ss_strand_t * nsp;
743
744 v9p = (sparcv9_cpu_t *)(sp->specificp);
745 nsp = v9p->impl_specificp;
746 SET_DTLB_FAULT( nsp, VA48(pc) );
747 v9p->post_precise_trap(sp, (sparcv9_trap_type_t) N2_trap_mem_address_range);
748 return true;
749 }
750#endif /* } */
751 return false;
752}
753
754
755
756
757#if WALL_TIME /* { */
758
759hrtime_t base_hrtime;
760
761/*ARGSUSED*/
762static void
763init_tick_counter_scale(tick_counter_t *tcp, uint64_t freq)
764{
765 if (!options.walltime)
766 return;
767
768 /* We convert gethrtime() to the simulated tick_counter frequency. */
769 tcp->scale = (double)freq / (double)NANOSEC;
770 tcp->scale_recip = 1.0 / tcp->scale;
771 if (base_hrtime == 0)
772 base_hrtime = RAW_HRTIME;
773}
774#endif /* } */
775
776
777static uint_t
778count_bits(uint64_t m)
779{
780 uint_t n;
781
782 for (n = 0; m != 0; m &= m-1)
783 n++;
784 return n;
785}
786
787static uint_t
788count_cores(uint64_t m)
789{
790 uint_t n;
791
792 for (n = 0; m != 0; m >>= STRANDSPERCORE)
793 n++;
794 return n + 1;
795}
796
797
798 /*
799 * Initialise the processor after parsing is complete
800 * In this case we create a number of SPARC v9 sparccpu_t
801 * one per strand available in this processor.
802 */
803
804void ss_init(domain_t * domainp, config_proc_t * config_procp)
805{
806 extern void debug_init(simcpu_t *sp);
807 uint_t ncpus;
808 ss_proc_t * pnp;
809 uint_t idx, core, vthread;
810 uint_t vcore_id;
811 uint64_t core_avail = 0, core_running = 0;
812 ss_tlb_t * dtlbp, * itlbp, * tlbp;
813 sparcv9_cpu_t * tick_v9p = NULL;
814 uint_t ncores;
815 uint64_t tmp_core_mask;
816
817 pnp = (ss_proc_t*)(config_procp->procp);
818
819 /*
820 * OK for each core and vthread create a sparc v9 CPU
821 * with appropriate call backs to the SunSPARC CPU module for
822 * CPU specific components.
823 */
824
825 /*
826 * FIXME: due to core indexing of some arrays, we get the
827 * max core number plus one.
828 */
829 ncores = count_cores(pnp->core_mask);
830 ncpus = count_bits(pnp->core_mask);
831 pnp->nstrands = ncpus;
832
833 pnp->strand = Xcalloc(ncpus, sparcv9_cpu_t *);
834
835 /* Note: allocate actual structs - NOT pointer list */
836 pnp->ss_strandp = Xcalloc(ncpus, ss_strand_t);
837
838 /* Init HW strand# to ss_strandp[]/starnd[] index table */
839 for (idx = 0; idx < STRANDS_PER_CHIP; idx++)
840 pnp->str_to_idx[idx] = NO_STRAND;
841
842#ifdef ROCK /* { */
843 ASSERT(ncpus <= STRANDS_PER_CHIP);
844 /*
845 * Rock has only one Unified (IMMU and DMMU) TLB per chip.
846 */
847 pnp->tlbp = Xcalloc(1, ss_tlb_t);
848 tlbp = pnp->tlbp;
849 ss_tlb_init(tlbp, pnp->tlbspec.nentries);
850 tlbp->parity = pnp->tlbspec.parity;
851 tlbp->lru_array = Xcalloc(ROCK_TLB_SETS, uint8_t);
852
853 /*
854 * Create Reverse Mapped Table for Rock interrupts
855 */
856 pnp->rmt_basep = Xcalloc(STRANDS_PER_CHIP, uint64_t);
857
858 /* FIXME: set to false by reset, true by running 0->non-0 */
859 pnp->sp_read_dis = true;
860 pnp->sp_write_dis = true;
861
862#endif /* } */
863
864 pnp->ndtlb = ncores;
865 pnp->nitlb = ncores;
866 pnp->dtlbp = Xcalloc(pnp->ndtlb, ss_tlb_t);
867 pnp->itlbp = Xcalloc(pnp->nitlb, ss_tlb_t);
868
869 pnp->icachep = Xcalloc(ncores, ss_l1_cache_t);
870 pnp->dcachep = Xcalloc(ncores, ss_l1_cache_t);
871
872#if INTERNAL_BUILD /* { */
873#ifdef NIAGARA1
874 pnp->mod_arith_p = (mod_arith_t *) Xcalloc(ncores, mod_arith_t);
875 (void) pthread_mutex_init(&pnp->mod_arith_p->lock, NULL);
876#endif
877#ifdef NIAGARA2
878 pnp->stream_cwq_p = (asi_stream_CWQ_t *) Xcalloc(ncores, asi_stream_CWQ_t);
879 pnp->mod_arith_p = (asi_stream_MA_t *) Xcalloc(ncores, asi_stream_MA_t);
880 (void) pthread_mutex_init(&pnp->stream_cwq_p->cwq_mtx, NULL);
881 (void) pthread_cond_init(&pnp->stream_cwq_p->cwq_cv, NULL);
882 (void) pthread_mutex_init(&pnp->mod_arith_p->ma_mtx, NULL);
883 (void) pthread_cond_init(&pnp->mod_arith_p->ma_cv, NULL);
884#endif
885#endif /* INTERNAL_BUILD } */
886
887#ifdef NIAGARA2
888 /* Initialised to zeros by default */
889 pnp->sparc_power_mgmtp = Xcalloc(ncores, sparc_power_mgmt_t);
890#endif
891
892
893#if ERROR_INJECTION /* { */
894 pnp->pend_errlistp = domainp->errlistp;
895 pthread_mutex_init(&pnp->err_lock, NULL);
896 pnp->errorp = Xcalloc(1, error_proc_t);
897 pnp->error_check = false;
898#endif /* } */
899
900#ifdef ROCK /* { */
901 pthread_mutex_init(&pnp->ucr_lock, NULL);
902 pthread_mutex_init(&pnp->tw_lock, NULL);
903#endif /* } */
904
905#if ERROR_TRAP_GEN /* { */
906 ss_error_trap_proc_init(config_procp);
907#endif /* } ERROR_TRAP_GEN */
908
909#if defined(ROCK) /* { */
910 tick_v9p = NULL;
911#endif /* } */
912
913 tmp_core_mask = pnp->core_mask;
914
915 idx = 0;
916 for (core=0; core < CORESPERCHIP; core++,
917 tmp_core_mask >>= STRANDSPERCORE) {
918 ss_l1_cache_t * icachep, * dcachep;
919
920 /* skip cores with no strands */
921 if ((tmp_core_mask & ((1u << STRANDSPERCORE) - 1)) == 0)
922 continue;
923
924 /* First init the TLB structures each core uses */
925 itlbp = &(pnp->itlbp[core]);
926 dtlbp = &(pnp->dtlbp[core]);
927
928 ss_tlb_init(itlbp, pnp->itlbspec.nentries);
929 itlbp->parity = pnp->itlbspec.parity;
930 ss_tlb_init(dtlbp, pnp->dtlbspec.nentries);
931 dtlbp->parity = pnp->dtlbspec.parity;
932
933 icachep = &(pnp->icachep[core]);
934 dcachep = &(pnp->dcachep[core]);
935
936 ss_l1_cache_init(icachep, SS_ICACHE_SIZE, true);
937 ss_l1_cache_init(dcachep, SS_DCACHE_SIZE, false);
938
939#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
940 tick_v9p = NULL;
941#endif /* } */
942
943 for (vthread=0; vthread < STRANDSPERCORE; vthread++) {
944 sparcv9_cpu_t * v9p;
945 ss_strand_t * nsp;
946 simcpu_t * sp;
947
948 /* skip missing strands */
949 if ((tmp_core_mask & (1u << vthread)) == 0)
950 continue;
951
952 /* Need something here to determine which
953 * scheduler wheel the simcpu_t ends up on.
954 */
955 v9p = sparcv9_cpu_alloc(domainp,
956 config_procp,
957 pnp->nwins, pnp->nglobals, pnp->maxtl,
958 pnp->ver, pnp->has_fpu,
959 pnp);
960
961 pnp->strand[idx] = v9p;
962
963 /*
964 * Tie to SunSPARC CPU specific info
965 */
966
967 nsp = &(pnp->ss_strandp[idx]);
968 sp = v9p->simp;
969
970#if 0
971 EXEC_WARNING(("ss_init: core: %u strand: %u idx: %u nsp: %p sp: %p", core, vthread, idx, nsp, sp));
972#endif
973
974 v9p->impl_specificp = nsp;
975
976 v9p->read_state_reg = ss_read_state_reg;
977 v9p->write_state_reg = ss_write_state_reg;
978 v9p->read_priv_reg = ss_read_priv_reg;
979 v9p->write_priv_reg = ss_write_priv_reg;
980 v9p->read_hyp_priv_reg = ss_read_hyp_priv_reg;
981 v9p->write_hyp_priv_reg = ss_write_hyp_priv_reg;
982 v9p->check_vahole = ss_check_vahole;
983 v9p->done_retry = ss_done_retry;
984 v9p->jpriv = ss_jpriv;
985 v9p->asi_access = ss_asi_access;
986 v9p->post_precise_trap = ss_post_precise_trap;
987
988 /*
989 * Initialize shared tick/stick register pointers.
990 */
991#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
992 if (tick_v9p == NULL) {
993 tick_v9p = v9p;
994#if WALL_TIME /* { */
995 init_tick_counter_scale(&tick_v9p->_tick,
996 pnp->clkfreq);
997#endif /* } */
998 }
999 /* STICK is an alias of TICK */
1000 v9p->stick = v9p->tick = &tick_v9p->_tick;
1001#elif ROCK /* } { */
1002 if (tick_v9p == NULL) {
1003 tick_v9p = v9p;
1004#if WALL_TIME /* { */
1005 init_tick_counter_scale(&tick_v9p->_tick,
1006 pnp->clkfreq);
1007 init_tick_counter_scale(&tick_v9p->_stick,
1008 domainp->sysclkfreq);
1009#endif /* } */
1010 }
1011 v9p->tick = &tick_v9p->_tick;
1012 v9p->stick = &tick_v9p->_stick;
1013#else /* } { */
1014#error "No valid processor defined."
1015#endif /* } */
1016
1017 v9p->tick_cmpr.counter = v9p->tick;
1018 v9p->stick_cmpr.counter = v9p->stick;
1019 v9p->hstick_cmpr.counter = v9p->stick;
1020
1021 sp->cycle_target_match = ss_cycle_target_match;
1022
1023 /*
1024 * determine virtual core ID
1025 */
1026 nsp->core = core;
1027 nsp->vthread = vthread;
1028 vcore_id = (core << SS_COREID_SHIFT) | vthread;
1029 nsp->vcore_id = vcore_id;
1030 pnp->str_to_idx[vcore_id] = idx;
1031 core_avail |= 1ull << vcore_id;
1032 /*
1033 * CMP states that the only the lowest numbered
1034 * strand starts executing.
1035 */
1036 if (core_running == 0)
1037 core_running |= 1ull << vcore_id;
1038#ifdef ROCK_FAKE_SP /* { */
1039 if (pnp->config_procp->domainp->systemp->fake_sp) {
1040 /*
1041 * SP initializes the current strand id
1042 * in a hyper scratch pad register.
1043 * Legion temporarily handles this job
1044 * by combining vcore_id and chip_id
1045 * in HSCRATCH0 register.
1046 */
1047 nsp->strand_reg[SSR_HSCRATCHPAD_INDEX] =
1048 vcore_id |
1049 (pnp->fake_chip_id << RK_CHIP_ID_SHIFT);
1050DBGSCRATCH( lprintf(sp->gid, "HSCRATCH0 init 0x%llx\n",
1051 nsp->strand_reg[SSR_HSCRATCHPAD_INDEX]); );
1052 }
1053#endif /* } */
1054
1055 /*
1056 * set up the execution instruction cache for it
1057 */
1058 sp->xicachep = xicache_alloc(sp);
1059 sp->xic_miss = ss_xic_miss;
1060
1061 /*
1062 * Now set up the execution data cache ..
1063 */
1064 sp->xdc.miss = ss_xdc_miss;
1065
1066
1067#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
1068 /*
1069 * Init internal strand control registers
1070 */
1071 nsp->lsu_control_raw = LSU_CTRL_INITVAL;
1072 nsp->dmmu.enabled = (nsp->lsu_control_raw & LSU_CTRL_DMMU_EN) != 0;
1073 nsp->immu.enabled = (nsp->lsu_control_raw & LSU_CTRL_IMMU_EN) != 0;
1074
1075 /*
1076 * Init the strand's MMU ...
1077 */
1078 nsp->dmmu.is_immu = false;
1079 nsp->immu.is_immu = true;
1080
1081#elif ROCK /* } { */
1082 /*
1083 * Init internal strand control registers
1084 */
1085
1086 nsp->mmu.dmmu_enabled = false;
1087 nsp->mmu.immu_enabled = false;
1088
1089 /*
1090 * This is_immu field gets updated each time before it is used, but
1091 * just so that we have a starting point...
1092 */
1093 nsp->mmu.is_immu = false;
1094 nsp->tlbp = tlbp;
1095 tlbp->shares++;
1096
1097 /*
1098 * Initialize some Transactional Memory stuff.
1099 * N.B. tm_chkpt==NULL is taken to mean that this implementation
1100 * does not support chkpt instruction.
1101 * Similar assumption is made with respect to commit instruction.
1102 */
1103 nsp->tm_chkpt = ss_tm_chkpt;
1104 nsp->tm_commit = ss_tm_commit;
1105 nsp->tm_fail = ss_tm_fail;
1106 TM_SET_INACTIVE(nsp);
1107
1108 /*
1109 * TM is disabled by default in Legion. This is
1110 * enabled by hypervisor, dumbreset (reset.s)
1111 */
1112 pnp->dcucr[core] = 0;
1113 nsp->tm_enabled = false;
1114 nsp->cps = 0;
1115
1116 /* Floating Point Arithmetic Enable */
1117 nsp->fpae = false;
1118
1119 pthread_mutex_init(&nsp->ifucr_lock, NULL);
1120
1121#else /* } { */
1122#error "No valid processor defined."
1123#endif /* } */
1124 /*
1125 * Other misc stuff ...
1126 */
1127 nsp->dtlbp = dtlbp;
1128 dtlbp->shares++;
1129 nsp->itlbp = itlbp;
1130 itlbp->shares++;
1131 nsp->icachep = icachep;
1132 nsp->dcachep = dcachep;
1133
1134#if ERROR_INJECTION /* { */
1135 if (pnp->pend_errlistp)
1136 sp->error_priv = pnp->pend_errlistp->priv;
1137#endif /* } */
1138
1139#if PERFORMANCE_CHECK /* { */
1140 /* FIXME: HACK TO GO AWAY */
1141 sp->last_hrtime = gethrtime();
1142 sp->total_hrtime = 0;
1143 sp->perf_target = pnp->proc_debug.perf_cycle_gap;
1144
1145 sp->xdc_hits = 0;
1146 sp->xdc_misses = 0;
1147 sp->xdc_flushes = 0;
1148 sp->xic_hits = 0;
1149 sp->xic_misses = 0;
1150 sp->xic_flushes = 0;
1151
1152#endif /* } */
1153
1154 /*
1155 * Per-thread performance counter
1156 * initialization
1157 */
1158#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
1159 nsp->pic0 = 0;
1160 nsp->pic1 = 0;
1161 nsp->pcr = 0LL;
1162 RESET_PIC_SAMPLE_BASES(sp, nsp, v9p);
1163#endif /* } */
1164
1165
1166 /*
1167 * Initialise with power on reset
1168 */
1169 nsp->pending_precise_tt = SS_trap_NONE;
1170 nsp->pending_async_tt = SS_trap_NONE; /* FIXME ? */
1171
1172#if defined(NIAGARA2) || defined(ROCK) /* { */
1173 /*
1174 * Niagara2 calculates the CMP virtual CORE_ID[5:0]
1175 * and CORE_AVAIL[63:0] (physical core id in [5:3]
1176 * and strand id in [2:0]).
1177 *
1178 * for example, an N2 with 4 physical cores and 2 strands per core,
1179 * the virtual CORE_ID for the 8 strands would be numbered as
1180 * 0,1,8,9,16,17,24,25, and the CORE_AVAIL would be set to 0x3030303.
1181 *
1182 * Rock contains up to 16 cores (micro cores). Each
1183 * contains up to 2 strands. A config file specifies
1184 * 4 cores 1 thread would have strand ids numbered as
1185 * 0,2,4,6.
1186 */
1187
1188 /*
1189 * for Niagara 2, CPU's initial state is determined
1190 * by the initial value of asi_core_running_status
1191 * register
1192 */
1193 if (((1ull << vcore_id) & core_running) == 0) {
1194 SET_PARKED(sp);
1195 }
1196
1197 DBG( lprintf(sp->gid, "cpu0x%llx (%s)\n",
1198 nsp->vcore_id,
1199 RUNNABLE(sp) ?"Unparked":"Parked"); );
1200#endif /* } */
1201
1202
1203#if defined(NIAGARA1) /* { */
1204 /*
1205 * For Niagara, the CPU's initial state is that only one thread
1206 * will be running, the other threads are put in the idle state
1207 * and are then parked.
1208 * The Reset code for Niagara expects that only one cpu (can be
1209 * any one) will sign-on after a POR so we just choose the first
1210 * cpu (sp->gid ==0).
1211 *
1212 * Its like 'Highlander' - there can be only one !
1213 */
1214 if (sp->gid == 0) {
1215 SET_THREAD_STS_SFSM(pnp, nsp, THREAD_STS_TSTATE_RUN);
1216 CLR_PARKED(sp);
1217 } else {
1218 SET_THREAD_STS_SFSM(pnp, nsp, THREAD_STS_TSTATE_IDLE);
1219 SET_PARKED(sp);
1220 }
1221
1222 DBG( lprintf(sp->gid, "cpu0x%llx "
1223 "sfsm_state = 0x%llx (%s)\n",
1224 nsp->vcore_id, pnp->sfsm_state[nsp->vcore_id],
1225 RUNNABLE(sp) ?"Unparked":"Parked"); );
1226#endif /* } NIAGARA1 */
1227
1228 debug_init(sp);
1229
1230#if ERROR_TRAP_GEN /* { */
1231 ss_error_trap_strand_init(config_procp, sp);
1232#endif /* } ERROR_TRAP_GEN */
1233
1234 /* fake up a start of execution */
1235 sp->config_procp->proc_typep->exec_setup(sp);
1236
1237 /* do the reset */
1238 ss_reset_trap( sp, SS_trap_power_on_reset );
1239
1240 /* cleanup after "execution" */
1241 sp->config_procp->proc_typep->exec_cleanup(sp);
1242
1243 idx ++;
1244
1245 } /* for vtrhead */
1246
1247 } /* for core */
1248
1249#ifdef NIAGARA1 /* { */
1250 /*
1251 * For IOB: */
1252 pnp->core_avail = core_avail;
1253#endif /* } */
1254
1255#ifdef NIAGARA2 /* { */
1256 /*
1257 * Initialize CMP registers, each one is shared by all virtual cores.
1258 *
1259 * Implementation note on the storage:
1260 *
1261 * - asi_cmp_core_intr_id & asi_cmp_core_id are not stored internally
1262 * as they can be calculated on the fly
1263 *
1264 * - cmp_regs.core_enable_status stores
1265 *
1266 * asi_core_available
1267 * asi_core_enable_status
1268 * asi_core_enable
1269 *
1270 * - cmp_regs.core_running_status stores
1271 *
1272 * asi_core_running_rw
1273 * asi_core_running_w1s
1274 * asi_core_running_w1c
1275 * asi_core_running_status
1276 *
1277 */
1278 pnp->cmp_regs.core_enable_status = core_avail;
1279 pnp->cmp_regs.xir_steering = core_avail;
1280 pnp->cmp_regs.tick_enable = false;
1281 pnp->cmp_regs.core_running_status = core_running;
1282
1283 /* Also init tick_stop flag and its lock */
1284 pnp->tick_stop = true;
1285 pthread_mutex_init(&pnp->tick_en_lock, NULL);
1286#endif /* } */
1287
1288#ifdef ROCK_FAKE_SP /* { */
1289 /*
1290 * Revisit it when SP can provide data for these registers.
1291 */
1292 pnp->cmp_regs.strand_available = core_avail;
1293 if (simstatus.sp.mode != true) {
1294 pnp->cmp_regs.strand_enable = core_avail;
1295 pnp->cmp_regs.strand_running = core_running;
1296 pnp->cmp_regs.strand_running_status = core_running;
1297 } else {
1298 pnp->cmp_regs.strand_enable = 0;
1299 pnp->cmp_regs.strand_running = 0;
1300 ss_change_exec_state(pnp, 0);
1301 pnp->cmp_regs.strand_running_status = 0;
1302 }
1303#endif /* } */
1304
1305#ifdef NIAGARA1 /* { */
1306 pthread_mutex_init(&pnp->thread_sts_lock, NULL);
1307#endif /* } */
1308
1309#if defined(NIAGARA2) || defined(ROCK) /* { */
1310 pthread_mutex_init(&pnp->cmp_lock, NULL);
1311#endif /* } */
1312
1313#ifdef ROCK /* { */
1314 pnp->sp_intr_status = 0;
1315 pnp->spie_status = 1;
1316#endif /* } */
1317}
1318
1319
1320
1321 /*************************************************************
1322 *
1323 * Execution support functions (and instruction impls)
1324 *
1325 *************************************************************/
1326
1327
1328 /*
1329 * When execution starts some simcpu_t setup may be required
1330 */
1331
1332void ss_exec_setup(simcpu_t * sp)
1333{
1334 sparcv9_cpu_t * v9p = (sparcv9_cpu_t *)(sp->specificp);
1335
1336 sparcv9_active_window(sp, v9p->cwp);
1337 sparcv9_active_globals(sp, v9p->gl);
1338}
1339
1340
1341 /*
1342 * When execution stop some cleanup of state is required for debugger access
1343 */
1344
1345void ss_exec_cleanup(simcpu_t * sp)
1346{
1347 sparcv9_active_window(sp, -1);
1348 sparcv9_active_globals(sp, -1);
1349}
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359 /*
1360 * Functions to dump the SunSPARC processor state
1361 */
1362
1363void ss_dump(domain_t * domainp, config_proc_t * config_procp)
1364{
1365 ss_proc_t * procp;
1366
1367 procp = config_procp->procp;
1368
1369 pi("\t// processor node id %u\n", config_procp->proc_id);
1370 pi("processor \"%s\" {\n", config_procp->proc_typep->proc_type_namep);
1371 dumpinfo.indent++;
1372
1373 pi("clkfreq 0x%llx ;\n", procp->clkfreq);
1374 pi("core_mask 0x%llx ;\n", procp->core_mask);
1375 pi("nwins %u ;\n", procp->nwins);
1376 pi("maxtl %u ;\n", procp->maxtl);
1377 pi("ver 0x%p ;\n", procp->ver);
1378 if (!procp->has_fpu) pi("nofpu ;\n");
1379
1380 pi("rstv 0x%llx ;\n", procp->rstv_addr);
1381
1382 pi("itlb {\n");
1383 dumpinfo.indent++;
1384 pi("entries %u;\n", procp->itlbspec.nentries);
1385 if (procp->itlbspec.parity)
1386 pi("parity;\n");
1387 dumpinfo.indent--;
1388 pi("}\n");
1389 pi("dtlb {\n");
1390 dumpinfo.indent++;
1391 pi("entries %u;\n", procp->dtlbspec.nentries);
1392 if (procp->dtlbspec.parity)
1393 pi("parity;\n");
1394 dumpinfo.indent--;
1395 pi("}\n");
1396#if defined(ROCK) /* Rock has a unified L2 TLB also */
1397 pi("unified_tlb {\n");
1398 dumpinfo.indent++;
1399 pi("entries %u;\n", procp->tlbspec.nentries);
1400 if (procp->tlbspec.parity)
1401 pi("parity;\n");
1402 dumpinfo.indent--;
1403 pi("}\n");
1404#endif
1405
1406 dumpinfo.indent--;
1407 pi("}\n");
1408}
1409
1410
1411bool_t ss_dev_mem_access(config_proc_t *config_procp, tpaddr_t addr, uint8_t *datap,
1412 uint64_t size, dev_access_t type)
1413{
1414 domain_t *domainp;
1415 config_addr_t *config_addrp;
1416 tpaddr_t extent;
1417 uint8_t *bufp;
1418
1419 domainp = config_procp->domainp;
1420
1421 config_addrp = find_domain_address(domainp, addr);
1422 if (config_addrp == NULL) {
1423 EXEC_WARNING(("ss_dev_mem_access: physical address 0x%llx not valid", addr));
1424 return false;
1425 }
1426
1427 /*
1428 * For now only handle cacheable device memory
1429 */
1430 extent = config_addrp->config_devp->dev_typep->dev_cacheable(config_addrp, type,
1431 addr-config_addrp->baseaddr, &bufp);
1432 if (extent < size) {
1433 EXEC_WARNING(("ss_dev_mem_access: physical address 0x%llx out of range 0x%llx",
1434 addr, extent));
1435 return false;
1436 }
1437
1438 /*
1439 * Do memory read/write between physical memory (pointed by 'bufp')
1440 * and device memory (pointed by 'datap')
1441 */
1442 switch (type) {
1443 case DA_Load:
1444 memcpy(datap, bufp, size);
1445 break;
1446 case DA_Store:
1447 memcpy(bufp, datap, size);
1448 break;
1449 default:
1450 ASSERT(0);
1451 }
1452
1453 return true;
1454}
1455
1456
1457
1458 /*
1459 *------------------------------------------------------------
1460 *
1461 * Debugger and generic interface code ..
1462 * ... mostly vectoring into the V9 code.
1463 *
1464 *------------------------------------------------------------
1465 */
1466
1467
1468
1469void * ss_dbgr_attach(domain_t * domainp, config_proc_t * config_procp, char * attach_strp)
1470{
1471 ss_dbgr_t * ndp;
1472 ss_proc_t * np;
1473
1474 np = (ss_proc_t*)(config_procp->procp);
1475
1476 ndp = Xcalloc(1, ss_dbgr_t);
1477
1478 /* For now just fake up attaching to core 0 strand 0 FIXME */
1479
1480 ndp->domainp = domainp;
1481 ndp->config_procp = config_procp;
1482 ndp->core = 0;
1483 ndp->strand = 0;
1484
1485 ndp->strandp = np->strand[0];
1486
1487 return (void*)ndp;
1488}
1489
1490
1491
1492
1493void ss_dbgr_detach(void * ptr)
1494{
1495 ss_dbgr_t * ndp = (ss_dbgr_t*)ptr;
1496
1497 /* Clean up SunSPARC specific debugger state FIXME */
1498
1499 Xfree(ndp);
1500}
1501
1502
1503
1504 /*
1505 * read internal register ...
1506 * ... returns false on failure ...
1507 * should we specific regname, and not a number ? FIXME
1508 */
1509
1510bool_t ss_dbgr_regread(void * ptr, uint_t regnum, uint64_t * valp)
1511{
1512 ss_dbgr_t * ndp = (ss_dbgr_t *)ptr;
1513 sparcv9_cpu_t * sp = ndp->strandp;
1514
1515 /* Check for any SunSPARC specific regs first */
1516
1517 return sparcv9_regread(sp, regnum, valp);
1518}
1519
1520
1521 /* returns false on failure */
1522
1523bool_t ss_dbgr_regwrite(void * ptr, uint_t regnum, uint64_t val)
1524{
1525 ss_dbgr_t * ndp = (ss_dbgr_t *)ptr;
1526 sparcv9_cpu_t * sp = ndp->strandp;
1527
1528 /* Check for any SunSPARC specific regs first */
1529
1530 return sparcv9_regwrite(sp, regnum, val);
1531}
1532
1533
1534uint64_t ss_dbgr_mem_read(void * ptr, tvaddr_t vaddr, bool_t do_translate, uint8_t * bufp, uint64_t len)
1535{
1536 ss_dbgr_t * ndp = (ss_dbgr_t *)ptr;
1537
1538 return ss_cpu_mem(
1539 ndp->domainp,
1540 ndp->config_procp->procp,
1541 ndp->strandp,
1542 NA_mem_read,
1543 vaddr, do_translate,
1544 bufp, len);
1545}
1546
1547
1548uint64_t ss_dbgr_mem_write(void * ptr, tvaddr_t vaddr, bool_t do_translate, uint8_t * bufp, uint64_t len)
1549{
1550 ss_dbgr_t * ndp = (ss_dbgr_t *)ptr;
1551
1552 return ss_cpu_mem(
1553 ndp->domainp,
1554 ndp->config_procp->procp,
1555 ndp->strandp,
1556 NA_mem_write,
1557 vaddr, do_translate,
1558 bufp, len);
1559}
1560
1561
1562
1563uint64_t ss_dbgr_mem_clear(void * ptr, tvaddr_t vaddr, bool_t do_translate, uint64_t len)
1564{
1565 ss_dbgr_t * ndp = (ss_dbgr_t *)ptr;
1566
1567 return ss_cpu_mem(
1568 ndp->domainp,
1569 ndp->config_procp->procp,
1570 ndp->strandp,
1571 NA_mem_clear,
1572 vaddr, do_translate,
1573 (void*)0, len);
1574}
1575
1576
1577uint64_t
1578ss_cpu_mem(
1579 domain_t * domainp,
1580 void *procp_param,
1581 sparcv9_cpu_t * strandp,
1582 dbgr_mem_op_t memop,
1583 tvaddr_t addr,
1584 bool_t do_translate,
1585 uint8_t * bp,
1586 uint_t len)
1587{
1588 uint64_t tx_count;
1589 uint64_t tx_size;
1590 uint64_t tx_left;
1591 uint8_t * bufp;
1592 uint64_t size;
1593 tvaddr_t va;
1594 ss_proc_t *procp = (ss_proc_t *)procp_param;
1595
1596 va = addr;
1597 bufp = (uint8_t*)bp;
1598 tx_size = len;
1599 tx_left = len;
1600
1601 /*
1602 * We keep going until either there is no
1603 * translation available, or the target memory
1604 * device fails us.
1605 * *valid_lenp tells us how much succeeded
1606 */
1607
1608 for (tx_count = 0LL; tx_count < tx_size; tx_count += size) {
1609 tpaddr_t pa;
1610 uint64_t vlen;
1611
1612 pa = (tpaddr_t)va;
1613
1614 size = tx_left;
1615 /* insane max !! */
1616 if (size >= (1LL<<30)) size = 1LL<<30;
1617
1618 /* First translate if necessary vtop */
1619 if (do_translate) {
1620 if (!ss_vtop_translate(procp, strandp,
1621 va, &pa, &vlen)) return false;
1622 if (size > vlen) size = vlen;
1623 }
1624
1625 /* Note: if cpu had virtual caches we'd have
1626 * to pass in VA here too
1627 */
1628 size = ss_pmem_op(domainp, procp, strandp, memop, pa, bufp, size);
1629 if (size == 0) break;
1630
1631 bufp += size;
1632 tx_left -= size;
1633 va += size;
1634 }
1635
1636 /* returns the amount successfully handled - 0 if failed */
1637 return tx_count;
1638}
1639
1640 /*
1641 * Handles the V to P conversion for us for a given strand.
1642 * Of course = 1:1 if in hypervisor mode. FIXME
1643 */
1644
1645static bool_t ss_vtop_translate( ss_proc_t * np, sparcv9_cpu_t * strandp, tvaddr_t va, tpaddr_t *pap, tvaddr_t * vlenp)
1646{
1647 /* HACK FOR NOW - FIXME */
1648 *pap = va;
1649 *vlenp = 0x10000-(va & 0xffff); /* round to end of 64K page ;-) */
1650
1651 return true;
1652}
1653
1654
1655
1656
1657
1658static tpaddr_t ss_pmem_op(
1659 domain_t * domainp,
1660 ss_proc_t * procp,
1661 sparcv9_cpu_t * strandp,
1662 dbgr_mem_op_t memop,
1663 tpaddr_t pa,
1664 uint8_t * bufp,
1665 tpaddr_t size )
1666{
1667 config_addr_t *config_addrp;
1668 tpaddr_t offset;
1669 tpaddr_t extent;
1670 uint8_t * cbp;
1671
1672 /*
1673 * Find the actual domain device
1674 */
1675
1676 config_addrp = find_domain_address(domainp, pa);
1677 if (config_addrp == NULL) return false;
1678
1679 /*
1680 * For now only handle cacheable device memory
1681 */
1682 extent = config_addrp->config_devp->dev_typep->dev_cacheable(config_addrp, DA_Other,
1683 pa-config_addrp->baseaddr, &cbp);
1684 if (extent == 0) return 0;
1685
1686 if (size > extent) size = extent;
1687
1688
1689 /*
1690 * Handle all the appropriate niagaraness here for the cache
1691 * models we have : FIXME
1692 */
1693
1694 /* operate on the cacheable state */
1695 switch (memop) {
1696 case NA_mem_read:
1697 memcpy( bufp, cbp, size);
1698 break;
1699
1700 case NA_mem_write:
1701 memcpy( cbp, bufp, size);
1702 break;
1703
1704 case NA_mem_clear:
1705 memset( cbp, 0, size);
1706 break;
1707 }
1708
1709 return size;
1710}
1711
1712
1713
1714 /*
1715 *------------------------------------------------------------
1716 * Breakpoint support
1717 *------------------------------------------------------------
1718 */
1719
1720void ss_dbgr_set_break(void * ptr, tvaddr_t bpaddr)
1721{
1722 ss_dbgr_t * ndp = (ss_dbgr_t *)ptr;
1723 sparcv9_cpu_t * sp = ndp->strandp;
1724
1725 /* Check for any SunSPARC specific regs first */
1726
1727 sparcv9_set_break(sp, bpaddr);
1728}
1729
1730
1731
1732void ss_dbgr_clear_break(void * ptr, tvaddr_t bpaddr)
1733{
1734 ss_dbgr_t * ndp = (ss_dbgr_t *)ptr;
1735 sparcv9_cpu_t * sp = ndp->strandp;
1736
1737 /* Check for any SunSPARC specific regs first */
1738
1739 sparcv9_clear_break(sp, bpaddr);
1740}
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753 /*------------------------------------------------------------*
1754 *
1755 * Interrupt support
1756 *
1757 *------------------------------------------------------------*/
1758
1759 /*
1760 * Typically called after any processor state change,
1761 * or interrupt operation.
1762 * The function will post and call attention to any pending
1763 * device interrupts that may be legitimately delivered
1764 * given the current processor state.
1765 *
1766 * Note that a trap is not invoked here - just the indication
1767 * that the simcpu should pay attention for one
1768 */
1769
1770void ss_check_interrupts(simcpu_t *sp)
1771{
1772 sparcv9_cpu_t * v9p;
1773 ss_strand_t * nsp;
1774
1775 v9p = (sparcv9_cpu_t *)(sp->specificp);
1776 nsp = v9p->impl_specificp;
1777
1778 /* OK - if interrupts enabled, can at least trigger timer interrupts */
1779
1780 /* FIXME: These trap posts should be in the trap management code */
1781 /* where priorities are correctly assigned */
1782
1783 /* NOTE:
1784 * Do not put returns in this function .. all possible traps should be
1785 * posted. The post_precise_trap function correctly determines priority.
1786 * Also, just because a trap is posted here not not mean that that will be the
1787 * next trap taken.
1788 */
1789
1790 switch (v9p->state) {
1791 case V9_User:
1792 case V9_Priv:
1793 /* hstick traps cant be blocked except at hpriv level */
1794 if (v9p->hstick_cmpr.pending) {
1795 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_hstick_match);
1796 }
1797
1798#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
1799 /* Device interrupts to hypervisor are not blockable in user/priv mode */
1800 /* vector should not need a lock for test ... */
1801 if (nsp->irq_vector) {
1802 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_interrupt_vector_trap);
1803 }
1804#endif /* } */
1805
1806#ifdef ROCK /* { */
1807 /*
1808 * these interrupts are non-maskable in user/priv mode
1809 */
1810 if (nsp->flag_queue_irq[RK_Q_hpriv_0]) {
1811 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)RK_trap_hyperprivileged_queue_0);
1812 }
1813 if (nsp->flag_queue_irq[RK_Q_hpriv_1]) {
1814 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)RK_trap_hyperprivileged_queue_1);
1815 }
1816#endif /* } */
1817
1818 if (v9p->pstate.int_enabled) {
1819
1820 if (nsp->flag_queue_irq[NA_Q_mondo]) {
1821 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_cpu_mondo_trap);
1822 }
1823 if (nsp->flag_queue_irq[NA_Q_device]) {
1824 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_dev_mondo_trap);
1825 }
1826 if (nsp->flag_queue_irq[NA_Q_resumable]) {
1827 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_resumable_error);
1828 }
1829 /*
1830 * non-resumable error queue is not checked by HW on niagara
1831 * only delivered by hypervisor
1832 */
1833
1834 if ((v9p->stick_cmpr.pending || v9p->tick_cmpr.pending) && (v9p->pil < 14)) {
1835 v9p->post_precise_trap(sp, Sparcv9_trap_interrupt_level_e);
1836 }
1837 if ((v9p->softint >> (v9p->pil +1)) != 0) {
1838 uint_t i;
1839 for (i=15; i > v9p->pil; i--) {
1840 if ((v9p->softint>>i)&1LL) {
1841 v9p->post_precise_trap(sp, Sparcv9_trap_interrupt_level_1+i-1);
1842 goto softint_caught;
1843 }
1844 }
1845 fatal("Internal error: softint triggered, but not found (softint=0x%llx, pil=0x%x)",
1846 (uint64_t)v9p->softint, v9p->pil);
1847softint_caught:;
1848 }
1849 }
1850 break;
1851
1852 case V9_HyperPriv:
1853 /* All disrupting traps are blockable in hpriv mode */
1854 if (v9p->pstate.int_enabled) {
1855#ifdef ROCK /* { */
1856 if (nsp->flag_queue_irq[RK_Q_hpriv_0]) {
1857 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)RK_trap_hyperprivileged_queue_0);
1858 }
1859 if (nsp->flag_queue_irq[RK_Q_hpriv_1]) {
1860 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)RK_trap_hyperprivileged_queue_1);
1861 }
1862#endif /* } */
1863
1864 if (v9p->hstick_cmpr.pending) {
1865 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_hstick_match);
1866 }
1867
1868#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
1869 if (nsp->irq_vector) {
1870 v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_interrupt_vector_trap);
1871 }
1872#endif /* } */
1873 }
1874 break;
1875
1876 case V9_RED:
1877 if (v9p->pstate.int_enabled) FIXME_WARNING(("Interrupts enabled in RED state not implemented!"));
1878 break;
1879
1880 default:
1881 ASSERT(0); /* must be in user, priv or H priv states here */
1882 }
1883
1884#if ERROR_TRAP_GEN /* { */
1885 ss_check_error_traps(sp);
1886#endif /* } ERROR_TRAP_GEN */
1887
1888}
1889
1890
1891
1892
1893
1894 /*
1895 * Very similar to check_interrupts, but only ever called
1896 * from the main execution loop when attention is called,
1897 * and the async_event flag is set.
1898 * This routine is responsible for posting a trap if an
1899 * externally generated (i.e. not by this executing thread)
1900 * asynchronous event has happened, and as a result the
1901 * changed cpu state results in a trap ...
1902 * .... however, we do not call post_precise_trap, since
1903 * this may not be precise, but *especially* since that function
1904 * causes a set_attention ... and we're already responding to that.
1905 * Instead, if a trap is necessary we deliberately just insert the trap
1906 * type into the pending_async_tt and set take_exception instead.
1907 *
1908 * By async, we mean asynchonous to the simcpu execution thread ...
1909 */
1910
1911
1912void ss_check_async_event(simcpu_t *sp)
1913{
1914 sp->async_event = false;
1915 ss_check_interrupts(sp);
1916}
1917
1918
1919 /*
1920 * This is the temporary callback function for when we get a cycle count
1921 * match.
1922 * The idea is that one of our cycle counters has reached its target value
1923 * and so we go off to set the appropriate interrupt flags if enabled, and
1924 * then reschedule the next target interrupt.
1925 */
1926/*
1927 * Since the cycle_base's count at different rates, the match
1928 * is (now >= target) && !triggered. triggered is cleared
1929 * when *tick_cmpr is written and set on reset.
1930 */
1931
1932static void ss_cycle_target_match(simcpu_t *sp)
1933{
1934 ss_strand_t * nsp;
1935 ss_proc_t * npp;
1936 sparcv9_cpu_t * v9p;
1937 simcycle_t now;
1938 ticktarg_t now_targ;
1939 error_conf_t * ep;
1940 bool_t chk_intr = false;
1941
1942 v9p = (sparcv9_cpu_t *)(sp->specificp);
1943 nsp = v9p->impl_specificp;
1944 npp = (ss_proc_t *)(sp->config_procp->procp);
1945
1946 now = sp->cycle;
1947
1948#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
1949 /*
1950 * Check for Performance Counter match
1951 */
1952 if (nsp->pcr & SS_PCR_UT_ST) {
1953 uint32_t old_pic0, old_pic1;
1954 uint64_t old_pcr;
1955
1956 old_pic0 = nsp->pic0;
1957 old_pic1 = nsp->pic1;
1958 UPDATE_PIC(sp, nsp, v9p);
1959 old_pcr = nsp->pcr;
1960 /* approximate overflow detection by testing for PIC decrease */
1961 if (nsp->pic0 < old_pic0) {
1962 DBGPIC( lprintf(sp->gid, "Performance Counter Overflow pic0 @ cycle=0x%llx," \
1963 " pic0=0x%x, pic1=0x%x\n",
1964 now, nsp->pic0, nsp->pic1); );
1965 nsp->pcr |= SS_PCR_OV0; /* set OVFL */
1966 }
1967 if (nsp->pic1 < old_pic1) {
1968 DBGPIC( lprintf(sp->gid, "Performance Counter Overflow pic1 @ cycle=0x%llx," \
1969 " pic0=0x%x, pic1=0x%x\n",
1970 now, nsp->pic0, nsp->pic1); );
1971 nsp->pcr |= SS_PCR_OV1; /* set OVFH */
1972 }
1973 if (nsp->pcr != old_pcr) {
1974 v9p->softint |= BIT(15);
1975 DBGSOFTINT( lprintf(sp->gid,
1976 "softint pic overflow: pc=0x%llx, o7=0x%llx, val=0x%llx, stick=%u, tick=%u\n",
1977 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->softint, v9p->stick_cmpr.pending,
1978 v9p->tick_cmpr.pending); );
1979 chk_intr = true;
1980 }
1981 }
1982#endif /* } */
1983
1984
1985#if ERROR_TRAP_GEN /* { */
1986 if (now >= sp->error_cycle) {
1987 lprintf(sp->gid, "ERROR_TRAP_GEN: cycle target matched [0x%llx] at "\
1988 "instn_cnt 0x%llx\n", sp->error_cycle, now);
1989 sp->error_cycle = UINT64_MAX;
1990 sp->error_cycle_reached = true;
1991 }
1992#endif /* ERROR_TRAP_GEN } */
1993
1994
1995#if WALL_TIME
1996 if (options.walltime)
1997 now_targ = RAW_HRTIME;
1998 else
1999#endif /* WALL_TIME */
2000 now_targ = now;
2001 if (!v9p->tick_cmpr.triggered && now_targ >= v9p->tick_cmpr.target) {
2002 ASSERT( v9p->tick_cmpr.interrupt_enabled );
2003 v9p->tick_cmpr.triggered = true;
2004 v9p->tick_cmpr.pending = true;
2005 chk_intr = true;
2006 DBGSOFTINT( lprintf(sp->gid,
2007 "softint update: pc=0x%llx, o7=0x%llx, val=0x%llx, stick=%u, tick=%u\n",
2008 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->softint, v9p->stick_cmpr.pending,
2009 v9p->tick_cmpr.pending); );
2010 }
2011
2012 if (!v9p->stick_cmpr.triggered && now_targ >= v9p->stick_cmpr.target) {
2013 ASSERT( v9p->stick_cmpr.interrupt_enabled );
2014 v9p->stick_cmpr.triggered = true;
2015 v9p->stick_cmpr.pending = true;
2016 chk_intr = true;
2017 DBGSOFTINT( lprintf(sp->gid,
2018 "softint update: pc=0x%llx, o7=0x%llx, val=0x%llx, stick=%u, tick=%u\n",
2019 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->softint, v9p->stick_cmpr.pending,
2020 v9p->tick_cmpr.pending); );
2021 }
2022
2023 if (!v9p->hstick_cmpr.triggered && now_targ >= v9p->hstick_cmpr.target) {
2024 ASSERT( v9p->hstick_cmpr.interrupt_enabled );
2025 v9p->hstick_cmpr.triggered = true;
2026 v9p->hstick_cmpr.pending = true;
2027 chk_intr = true;
2028 DBGSOFTINT( lprintf(sp->gid,
2029 "hintp update: pc=0x%llx, o7=0x%llx, hintp=%u\n",
2030 sp->pc, sp->intreg[Reg_sparcv9_o7],
2031 v9p->hstick_cmpr.pending); );
2032 }
2033
2034 if ((now >= options.save_restore.trigger_icount) &&
2035 (options.save_restore.trigger_icount != 0)) {
2036 uint64_t c;
2037
2038 /*
2039 * Any cpu can hit this trigger point but we only
2040 * want one cpu to send the SAVE_STATE trap to all
2041 * strands in all processors.
2042 */
2043 c = host_cas64(&options.save_restore.trigger_icount,
2044 options.save_restore.trigger_icount, 0);
2045
2046 if (c != 0) {
2047 int i;
2048 domain_t *dp;
2049
2050 lprintf(sp->gid,
2051 "options.save_restore.trigger_icount reached. trigger=0x%llx, icount=0x%llx\n",
2052 c, now);
2053
2054 dp = sp->config_procp->domainp;
2055 for (i=0; i<dp->procs.count; i++) {
2056 config_proc_t * cp;
2057
2058 cp = LIST_ENTRY(dp->procs, i);
2059 cp->proc_typep->ext_signal(cp, ES_LEGION_SAVE_STATE, NULL);
2060 }
2061 }
2062 }
2063
2064#if ERROR_INJECTION /* { */
2065 /*
2066 * Turn on the error_enabled flag to begin checking for error
2067 * conditions. Flush caches so all subsequent instruction
2068 * fetches and ld/st operations are detected by the error handling
2069 */
2070 ep = NULL;
2071 pthread_mutex_lock(&npp->err_lock);
2072 if (npp->pend_errlistp && now == npp->pend_errlistp->cycle) {
2073 DBGERR( lprintf(sp->gid, "ss_cycle_target_match(): error cycle\n"); );
2074
2075 while (npp->pend_errlistp && now == npp->pend_errlistp->cycle) {
2076 ep = npp->pend_errlistp;
2077 npp->pend_errlistp = ep->nextp;
2078 if (sp->errorp->errlistp)
2079 ep->nextp = sp->errorp->errlistp;
2080 else
2081 ep->nextp = NULL;
2082 sp->errorp->errlistp = ep;
2083 }
2084 }
2085 pthread_mutex_unlock(&npp->err_lock);
2086
2087 if (ep) {
2088 sp->error_enabled = true;
2089 sp->error_check = (v9p->state == sp->error_priv) ? true : false;
2090 update_errflags(sp);
2091
2092 DBGERR( dump_errconf(sp->errorp->errlistp); );
2093 DBGERR( lprintf(sp->gid, "check_xicache = %u check_xdcache = %u\n",
2094 sp->errorp->check_xicache, sp->errorp->check_xdcache); );
2095
2096 sp->xicache_trans_flush_pending = true;
2097 sp->xdcache_trans_flush_pending = true;
2098 }
2099#endif /* ERROR_INJECTION } */
2100
2101#if PERFORMANCE_CHECK /* { */
2102 if (now >= sp->perf_target) {
2103 hrtime_t hrt, gap;
2104 double mips, amips;
2105
2106 hrt = gethrtime();
2107
2108 gap = hrt - sp->last_hrtime;
2109 sp->total_hrtime += gap;
2110
2111 mips = (1.0e3*(double)(ICOUNT(sp) - sp->prev_icount)) / (double)gap;
2112 amips =(1.0e3*(double)ICOUNT(sp)) / (double)sp->total_hrtime;
2113 log_lock();
2114 log_printf(sp->gid, "Simulator mips=%.2lf, average mips=%.2lf, "\
2115 "total_time=%llu seconds, delta_time=%llu milliseconds\n",
2116 mips, amips, HRT_TO_SEC(sp->total_hrtime), HRT_TO_MILLISEC(gap));
2117
2118 sp->config_procp->proc_typep->perf_dump(sp->specificp);
2119
2120 log_flush_unlock();
2121
2122 /* Don't count the time spent printing... */
2123 sp->last_hrtime = gethrtime();
2124
2125 /*
2126 * exit_at is parsed from the conf file.
2127 * If it's non-zero, we exit the simulator when we reach or
2128 * exceed that number of instns
2129 */
2130 if ((npp->proc_debug.exit_at != 0) &&
2131 (ICOUNT(sp) >= npp->proc_debug.exit_at)) {
2132 fatal("Reached the value for exit_at in conf file "
2133 "0x%llx, current icount=llu\n",
2134 npp->proc_debug.exit_at, ICOUNT(sp));
2135 }
2136
2137#if WALL_TIME
2138 if (options.walltime) {
2139 sp->perf_target = now + npp->proc_debug.perf_cycle_gap;
2140 ASSERT(sp->perf_target > sp->cycle);
2141 } else
2142#endif /* WALL_TIME */
2143 sp->perf_target += npp->proc_debug.perf_cycle_gap;
2144 }
2145#endif /* PERFORMANCE_CHECK } */
2146
2147 ss_recomp_cycle_target(sp);
2148 if (chk_intr)
2149 ss_check_interrupts(sp);
2150}
2151
2152
2153
2154
2155 /*------------------------------------------------------------*
2156 *
2157 * Privileged and status registers accessed here ...
2158 *
2159 *------------------------------------------------------------*/
2160
2161
2162
2163uint64_t ss_read_pstate(sparcv9_cpu_t * v9p)
2164{
2165 uint64_t pstate;
2166
2167 pstate = v9p->pstate.priv ? (1<<V9_PSTATE_PRIV_BIT) : 0;
2168 pstate |= v9p->pstate.mm << V9_PSTATE_MM_BITS;
2169 pstate |= v9p->pstate.int_enabled ? (1<< V9_PSTATE_IE_BIT) : 0;
2170 pstate |= v9p->pstate.addr_mask ? (1<< V9_PSTATE_AM_BIT) : 0;
2171 pstate |= v9p->pstate.fpu_enabled ? (1<< V9_PSTATE_PEF_BIT) : 0;
2172 pstate |= v9p->pstate.tle ? (1<< V9_PSTATE_TLE_BIT) : 0;
2173 pstate |= v9p->pstate.cle ? (1<< V9_PSTATE_CLE_BIT) : 0;
2174 pstate |= v9p->pstate.tct ? (1<< V9_PSTATE_TCT_BIT) : 0;
2175
2176 return pstate;
2177}
2178
2179
2180static uint64_t ss_read_hpstate(sparcv9_cpu_t * v9p)
2181{
2182 uint64_t hpstate;
2183
2184 hpstate = v9p->hpstate.hpriv ? (1<<V9_HPSTATE_HPRIV_BIT) : 0;
2185 hpstate |= v9p->hpstate.tlz ? (1<<V9_HPSTATE_TLZ_BIT) : 0;
2186 hpstate |= v9p->hpstate.red ? (1<<V9_HPSTATE_RED_BIT) : 0;
2187#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2188 hpstate |= v9p->hpstate.ibe ? (1<<V9_HPSTATE_IBE_BIT) : 0;
2189#endif /* } */
2190
2191#if defined(NIAGARA1)
2192 hpstate |= (1LL<<NA_HPSTATE_ENB_BIT);
2193#elif NIAGARA2
2194 /* Nothing extra for NIAGARA2 */
2195#elif ROCK
2196 {
2197 ss_strand_t * ssr = (ss_strand_t *)v9p->impl_specificp;
2198 hpstate |= ssr->tick_npt ? (1LL<<HPSTATE_TNPT_BIT) : 0;
2199 }
2200#else
2201#error "No valid processor defined."
2202#endif
2203
2204 return hpstate;
2205}
2206
2207
2208 /*
2209 * This function currently gets called by the done/retry
2210 * implementations as well as the wrpr instruction ...
2211 * ... we may want to settle on a distinct & more
2212 * efficient combined version for done/rety that
2213 * covers both pstate and hpstate -- FIXME
2214 */
2215
2216static void ss_write_pstate(simcpu_t * sp, uint64_t val)
2217{
2218 sparcv9_cpu_t * v9p;
2219 bool_t was_enabled;
2220
2221 v9p = (sparcv9_cpu_t *)(sp->specificp);
2222
2223 v9p->pstate.tle = BIT_TEST( val, V9_PSTATE_TLE_BIT ) ? true : false;
2224
2225 was_enabled = v9p->pstate.cle;
2226 v9p->pstate.cle = BIT_TEST( val, V9_PSTATE_CLE_BIT ) ? true : false;
2227 if (was_enabled != v9p->pstate.cle)
2228 sp->xdcache_trans_flush_pending = true;
2229
2230 was_enabled = v9p->fpu_on;
2231 v9p->pstate.fpu_enabled = BIT_TEST( val, V9_PSTATE_PEF_BIT ) ? true : false;
2232 v9p->fpu_on = v9p->pstate.fpu_enabled && v9p->fprs.fef && v9p->has_fpu;
2233#ifdef FP_DECODE_DISABLED
2234 /* flush instn cache to force new decodes - thus can trap on FP instructions */
2235 if ( v9p->fpu_on != was_enabled) {
2236 sp->xicache_instn_flush_pending = true;
2237 set_sync_pending(sp);
2238 }
2239#endif /* FP_DECODE_DISABLED */
2240
2241#ifdef ROCK
2242 v9p->pstate.mm = (val >> V9_PSTATE_MM_BITS) & V9_PSTATE_MM_MASK; /* Ignore effects */
2243#endif
2244
2245 v9p->pstate.addr_mask = BIT_TEST( val, V9_PSTATE_AM_BIT ) ? true : false;
2246 V9_PSTATE_AM_CHANGED(v9p);
2247
2248 v9p->pstate.int_enabled = BIT_TEST( val, V9_PSTATE_IE_BIT ) ? true : false;
2249 /* Have potentially just enabled a whole bunch of disrupting traps ... check them here */
2250 /* - handled by check interrupts call below */
2251
2252 v9p->pstate.tct = BIT_TEST( val, V9_PSTATE_TCT_BIT ) ? true : false;
2253 if ( v9p->pstate.tct ) IMPL_WARNING(("wr %%pstate: TCT=1 @ pc=0x%llx - TCT not supported", sp->pc));
2254
2255 was_enabled = v9p->pstate.priv;
2256 v9p->pstate.priv = BIT_TEST( val, V9_PSTATE_PRIV_BIT ) ? true : false;
2257 if (was_enabled != v9p->pstate.priv) {
2258 /* Change of execution state ? */
2259 if (v9p->state!=V9_HyperPriv && v9p->state!=V9_RED) {
2260 V9_STATE_CHANGE(sp, v9p, (v9p->pstate.priv ? V9_Priv : V9_User));
2261 }
2262 }
2263
2264 /* V9_PSTATE_CHANGED(v9p); */
2265
2266 ss_check_interrupts(sp); /* because of state change */
2267
2268 /*
2269 * Note: if interrupts were enabled, it is the next instructions
2270 * that would be observed as taking the trap (so we dont re-execute
2271 * the wrpr %pstate again after the return from trap.
2272 */
2273}
2274
2275
2276
2277
2278 /*
2279 * This function currently gets called by the done/retry
2280 * implementations as well as the wrpr instruction ...
2281 * ... we may want to settle on a distinct & more
2282 * efficient combined version for done/rety that
2283 * covers both pstate and hpstate -- FIXME
2284 */
2285
2286static void ss_write_hpstate(simcpu_t * sp, bool_t from_htstate, uint64_t val)
2287{
2288 uint64_t hpstate;
2289 sparcv9_cpu_t * v9p;
2290 bool_t flag_icflush = false;
2291 bool_t flag_dcflush = false;
2292 bool_t was_enabled;
2293 sparcv9_state_t new_state;
2294
2295 v9p = (sparcv9_cpu_t *)(sp->specificp);
2296
2297 v9p->hpstate.hpriv = BIT_TEST( val, V9_HPSTATE_HPRIV_BIT ) ? true : false;
2298 v9p->hpstate.tlz = BIT_TEST( val, V9_HPSTATE_TLZ_BIT ) ? true : false;
2299 v9p->hpstate.red = BIT_TEST( val, V9_HPSTATE_RED_BIT ) ? true : false;
2300
2301#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2302 v9p->hpstate.ibe = BIT_TEST( val, V9_HPSTATE_IBE_BIT ) ? true : false;
2303
2304 if (v9p->hpstate.ibe)
2305 IMPL_WARNING(("HPSTATE.IBE not implemented (pc=0x%llx)", sp->pc));
2306#endif /* } */
2307
2308 if (v9p->hpstate.tlz)
2309 IMPL_WARNING(("HPSTATE.TLZ not implemented (pc=0x%llx)", sp->pc));
2310
2311#if defined(NIAGARA1)
2312
2313 if (!from_htstate && !BIT_TEST(val, NA_HPSTATE_ENB_BIT))
2314 IMPL_WARNING(("ENB bit in hpstate cleared by executing code, but not implemented by legion (pc=0x%llx)", sp->pc));
2315
2316#elif NIAGARA2
2317 /* nothing to do */
2318#elif ROCK
2319 if (1 /* !from_htstate ?? */) {
2320 ss_strand_t * ssr = (ss_strand_t *)v9p->impl_specificp;
2321 ssr->tick_npt = BIT_TEST( val, HPSTATE_TNPT_BIT ) ? true : false;
2322 v9p->_tick.non_priv_trap = ssr->tick_npt;
2323 v9p->_stick.non_priv_trap = ssr->tick_npt;
2324 }
2325#else
2326#error "No valid processor defined."
2327#endif
2328
2329 if (v9p->hpstate.red) {
2330 new_state = V9_RED;
2331 } else
2332 if (v9p->hpstate.hpriv) {
2333 new_state = V9_HyperPriv;
2334 } else {
2335 new_state = v9p->pstate.priv ? V9_Priv : V9_User;
2336 }
2337
2338 if (v9p->state != new_state) {
2339 /* Have potentially just enabled a whole bunch of disrupting traps ... check them here */
2340 /* - handled by check interrupts call below */
2341
2342 V9_STATE_CHANGE(sp, v9p, new_state);
2343
2344 ss_check_interrupts(sp); /* because of state change */
2345 }
2346}
2347
2348
2349
2350
2351
2352
2353 /* tick is read as a pr and asr, so make code common here */
2354
2355uint64_t ss_read_tick(simcpu_t * sp)
2356{
2357 sparcv9_cpu_t * v9p;
2358 uint64_t val;
2359 ss_proc_t * npp = (ss_proc_t *)sp->config_procp->procp;
2360
2361 v9p = (sparcv9_cpu_t *)(sp->specificp);
2362 val = v9p->tick->offset + RAW_TICK(v9p);
2363
2364#ifdef NIAGARA1
2365 val &= MASK64(62, 2); /* Low bits are clear on Niagara */
2366#endif
2367
2368#ifdef NIAGARA2 /* { */
2369 if (npp->tick_stop)
2370 val = v9p->tick->offset;
2371#endif /* } */
2372
2373 return val;
2374}
2375
2376uint64_t ss_read_stick(simcpu_t * sp)
2377{
2378 sparcv9_cpu_t * v9p;
2379 uint64_t val;
2380 ss_proc_t * npp = (ss_proc_t *)sp->config_procp->procp;
2381
2382 v9p = (sparcv9_cpu_t *)(sp->specificp);
2383 val = v9p->stick->offset + RAW_STICK(v9p);
2384
2385#ifdef NIAGARA1
2386 val &= MASK64(62, 2); /* Low bits are clear on Niagara */
2387#endif
2388
2389#ifdef NIAGARA2 /* { */
2390 if (npp->tick_stop)
2391 val = v9p->stick->offset;
2392#endif /* } */
2393
2394 return val;
2395}
2396
2397
2398#if WALL_TIME
2399#define CALC_TARG(_tcmp) (options.walltime ? \
2400 (TICK_TO_HRT((_tcmp)->compare - (_tcmp)->counter->offset, \
2401 (_tcmp)->counter->scale_recip)) : \
2402 ((_tcmp)->compare - (_tcmp)->counter->offset))
2403#else /* WALL_TIME */
2404#define CALC_TARG(_tcmp) ((_tcmp)->compare - \
2405 (_tcmp)->counter->offset)
2406#endif /* WALL_TIME */
2407
2408#define RECALC_TARG(_sp, _tcmp) \
2409 (_tcmp)->target = CALC_TARG(_tcmp); \
2410 (_tcmp)->triggered = ((_tcmp)->target <= (_sp)->cycle)
2411
2412uint64_t ss_tick_cmpr_read(simcpu_t * sp, tick_compare_t *tcmp)
2413{
2414 return (tcmp->interrupt_enabled ? 0ULL : (1ULL << 63)) |
2415 tcmp->compare;
2416}
2417
2418void ss_tick_cmpr_write(simcpu_t * sp, tick_compare_t *tcmp, uint64_t val)
2419{
2420 ss_proc_t * npp;
2421
2422 npp = (ss_proc_t *)(sp->config_procp->procp);
2423
2424 tcmp->compare = val & MASK64(62,0);
2425 tcmp->interrupt_enabled = (val>>63) ? false : true;
2426 if (tcmp->interrupt_enabled) {
2427#ifdef NIAGARA2
2428 if (!npp->tick_stop) {
2429#endif
2430 RECALC_TARG(sp, tcmp);
2431#ifdef NIAGARA2 /* { */
2432 } else {
2433 /*
2434 * If tick is stopped, no need to update tick target
2435 * values as only sp->cycle is increasing, but
2436 * tick is stationary, so we will not hit the
2437 * target. The only exception to this is if,
2438 * while the tick is stopped, either the tick
2439 * counter or the tick_cmpr.compare is written
2440 * to such that they are both equal. Then we
2441 * need to have an interrupt happen right away.
2442 */
2443 if (tcmp->compare == tcmp->counter->offset)
2444 tcmp->target = sp->cycle + 1;
2445 else
2446 tcmp->triggered = true;
2447 tcmp->target = 0ull;
2448 }
2449#endif /* } */
2450 } else {
2451 /* "Don't do match compare" */
2452 tcmp->triggered = true;
2453 tcmp->target = 0;
2454 }
2455}
2456
2457
2458/*
2459 * Account for TICK/STICK offset changes.
2460 * TODO: must apply to all cmprs sharing the specific TICK/STICK.
2461 */
2462void ss_recomp_tick_target(simcpu_t * sp)
2463{
2464 sparcv9_cpu_t * v9p;
2465 ss_proc_t * npp;
2466
2467 npp = (ss_proc_t *)(sp->config_procp->procp);
2468
2469 v9p = (sparcv9_cpu_t *)(sp->specificp);
2470
2471#ifdef NIAGARA2
2472 if (!npp->tick_stop) {
2473#endif
2474
2475 if (v9p->tick_cmpr.interrupt_enabled) {
2476 RECALC_TARG(sp, &v9p->tick_cmpr);
2477 }
2478 if (v9p->stick_cmpr.interrupt_enabled) {
2479 RECALC_TARG(sp, &v9p->stick_cmpr);
2480 }
2481 if (v9p->hstick_cmpr.interrupt_enabled) {
2482 RECALC_TARG(sp, &v9p->hstick_cmpr);
2483 }
2484#ifdef NIAGARA2 /* { */
2485 } else {
2486 /*
2487 * If tick is stopped, no need to update tick target
2488 * values as only sp->cycle is increasing, but
2489 * tick is stationary, so we will not hit the
2490 * target. The only exception to this is if,
2491 * while the tick is stopped, either the tick
2492 * counter or the tick_cmpr.compare is written
2493 * to such that they are both equal. Then we
2494 * need to have an interrupt happen right away.
2495 */
2496 if (v9p->tick_cmpr.compare == v9p->tick_cmpr.counter->offset)
2497 v9p->tick_cmpr.target = sp->cycle + 1;
2498 else
2499 v9p->tick_cmpr.target = 0ull;
2500 if (v9p->stick_cmpr.compare == v9p->stick_cmpr.counter->offset)
2501 v9p->stick_cmpr.target = sp->cycle + 1;
2502 else
2503 v9p->stick_cmpr.target = 0ull;
2504 if (v9p->hstick_cmpr.compare == v9p->hstick_cmpr.counter->offset)
2505 v9p->hstick_cmpr.target = sp->cycle + 1;
2506 else
2507 v9p->hstick_cmpr.target = 0ull;
2508 }
2509#endif /* } */
2510
2511 DBGTICKREAD( lprintf(sp->gid,
2512 "recomp_tick_target: pc=0x%llx, cycle=0x%llx, tick_targ=0x%llx, "
2513 "stick_targ=0x%llx hstick_targ=0x%llx\n",
2514 sp->pc, sp->cycle, v9p->tick_cmpr.target, v9p->stick_cmpr.target,
2515 v9p->hstick_cmpr.target); );
2516
2517 ss_recomp_cycle_target(sp);
2518}
2519
2520
2521void ss_recomp_cycle_target(simcpu_t * sp)
2522{
2523 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
2524 simcycle_t now;
2525 simcycle_t old_target;
2526
2527#if ERROR_INJECTION /* { */
2528 ss_proc_t *npp;
2529 uint64_t error_cycle;
2530#endif /* } */
2531
2532#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2533 ss_strand_t *nsp = v9p->impl_specificp;
2534#endif /* } */
2535
2536 now = sp->cycle;
2537 old_target = sp->cycle_target;
2538 sp->cycle_target = UINT64_MAX;
2539
2540 /* For each of the following figure out the target value - assuming an
2541 * interrupt is enabled, then we figure out which is the nearest target
2542 */
2543
2544#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2545/*
2546 * Since the PIC implementation is not exact and the overflow traps
2547 * are disrupting (can be blocked sometimes), just cause a check
2548 * to happen every PIC_OVERFLOW_CHECK_INTERVAL cycles if counting is
2549 * enabled.
2550 */
2551#define PIC_OVERFLOW_CHECK_INTERVAL 1000
2552 if (nsp->pcr & SS_PCR_UT_ST) {
2553 if ((now + PIC_OVERFLOW_CHECK_INTERVAL) < sp->cycle_target)
2554 sp->cycle_target = (now + PIC_OVERFLOW_CHECK_INTERVAL);
2555 }
2556#endif /* } */
2557
2558/*
2559 * WALL_TIME_TARGET_POLL_HACK can go away once there is a running MIPS
2560 * average available to predict the right cycle_target. The gethrtime()
2561 * function traps to the kernel, so it would be inefficient to do that
2562 * for each instruction executed.
2563 */
2564#define WALL_TIME_TARGET_POLL_HACK 1000
2565#define CHECK_CMPR_TARGET(_tcmp) \
2566 if ((_tcmp)->target > now && \
2567 ((_tcmp)->target < sp->cycle_target)) \
2568 sp->cycle_target = options.walltime ? (sp->cycle) + WALL_TIME_TARGET_POLL_HACK : (_tcmp)->target
2569
2570 CHECK_CMPR_TARGET(&v9p->tick_cmpr);
2571 CHECK_CMPR_TARGET(&v9p->stick_cmpr);
2572 CHECK_CMPR_TARGET(&v9p->hstick_cmpr);
2573
2574 /* Check if save_restore trigger is the next trigger */
2575 if ((options.save_restore.trigger_icount > now) &&
2576 (options.save_restore.trigger_icount < sp->cycle_target))
2577 sp->cycle_target = options.save_restore.trigger_icount;
2578
2579
2580#if PERFORMANCE_CHECK
2581 if (sp->perf_target < sp->cycle_target)
2582 sp->cycle_target = sp->perf_target;
2583#endif
2584
2585#if ERROR_TRAP_GEN /* { */
2586 if (sp->error_cycle>now && sp->error_cycle<sp->cycle_target)
2587 sp->cycle_target = sp->error_cycle;
2588#endif /* ERROR_TRAP_GEN } */
2589
2590#if ERROR_INJECTION /* { */
2591 npp = (ss_proc_t *)(sp->config_procp->procp);
2592
2593 pthread_mutex_lock(&npp->err_lock);
2594 if (npp->pend_errlistp)
2595 error_cycle = npp->pend_errlistp->cycle;
2596 else
2597 error_cycle = 0;
2598 pthread_mutex_unlock(&npp->err_lock);
2599 if ((error_cycle > now) && (error_cycle < sp->cycle_target)) {
2600 sp->cycle_target = error_cycle;
2601 }
2602#endif /* } */
2603
2604 if (sp->cycle_target != old_target) {
2605 if (sp->cycle_target != UINT64_MAX) {
2606 ASSERT(sp->cycle_target >= sp->cycle);
2607 sp->exec_loop_reset = true;
2608 if (old_target == UINT64_MAX) {
2609 DBGTICK( lprintf(sp->gid,
2610 "recomp_cycle_target: pc=0x%llx, "
2611 "cycle=0x%llx cycle_target was never\n",
2612 sp->pc, sp->cycle); );
2613 }
2614 } else {
2615 DBGTICK( lprintf(sp->gid, "recomp_cycle_target: "
2616 "pc=0x%llx, cycle=0x%llx cycle_target set to "
2617 "never\n", sp->pc, sp->cycle); );
2618 }
2619 }
2620
2621 DBGTICKREAD( lprintf(sp->gid,
2622 "recomp_cycle_target: pc=0x%llx, cycle=0x%llx, "
2623 "cycle_target-cycle=0x%llx\n",
2624 sp->pc, sp->cycle, sp->cycle_target - sp->cycle); );
2625}
2626
2627
2628
2629
2630
2631void ss_write_tick(simcpu_t * sp, uint64_t val)
2632{
2633 sparcv9_cpu_t * v9p;
2634
2635 ss_proc_t * npp = (ss_proc_t *)sp->config_procp->procp;
2636 v9p = (sparcv9_cpu_t *)(sp->specificp);
2637
2638#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2639 /* NPT bit is per-strand, stick aliases to tick */
2640 v9p->_tick.non_priv_trap = (val >> 63) ? true : false;
2641 v9p->_stick.non_priv_trap = v9p->_tick.non_priv_trap;
2642#endif /* } */
2643 val &= 0x7fffffffffffffffLL;
2644 v9p->tick->offset = val - RAW_TICK(v9p);
2645
2646#ifdef NIAGARA2
2647 if (npp->tick_stop)
2648 v9p->tick->offset = val;
2649#endif
2650 ss_recomp_tick_target(sp);
2651}
2652
2653void ss_write_stick(simcpu_t * sp, uint64_t val)
2654{
2655 sparcv9_cpu_t * v9p;
2656 ss_proc_t *npp;
2657
2658 npp = (ss_proc_t *)(sp->config_procp->procp);
2659 v9p = (sparcv9_cpu_t *)(sp->specificp);
2660
2661#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2662 /* NPT bit is per-strand, stick aliases to tick */
2663 v9p->_tick.non_priv_trap = (val >> 63) ? true : false;
2664 v9p->_stick.non_priv_trap = v9p->_tick.non_priv_trap;
2665#endif /* } */
2666 val &= 0x7fffffffffffffffLL;
2667 v9p->stick->offset = val - RAW_STICK(v9p);
2668
2669#ifdef NIAGARA2
2670 if (npp->tick_stop)
2671 v9p->stick->offset = val;
2672#endif
2673
2674 ss_recomp_tick_target(sp);
2675}
2676
2677static void ss_read_state_reg(simcpu_t * sp, uint_t rdest, uint_t state_reg)
2678{
2679 uint64_t val;
2680 sparcv9_cpu_t * v9p;
2681 ss_strand_t * nsp;
2682
2683 v9p = (sparcv9_cpu_t *)(sp->specificp);
2684 nsp = v9p->impl_specificp;
2685
2686 switch (state_reg) {
2687 case 0x00: /* y */
2688#ifdef ROCK
2689 if (!nsp->fpae) {
2690 v9p->post_precise_trap(sp,
2691 Sparcv9_trap_illegal_instruction);
2692 return;
2693 }
2694#endif
2695 val = sp->v9_y;
2696 break;
2697 case 0x02: /* ccr */
2698 val = sp->v9_ccr;
2699 break;
2700 case 0x03: /* asi */
2701 val = sp->v9_asi;
2702 break;
2703 case 0x04: /* tick */
2704 if (v9p->state == V9_User && v9p->_tick.non_priv_trap) {
2705 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_action);
2706 return;
2707 }
2708 val = ss_read_tick(sp);
2709
2710#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2711 if (v9p->_tick.non_priv_trap) val |= 1ULL<<63;
2712#endif /* } */
2713 DBGTICKREAD( lprintf(sp->gid,
2714 "tick read asr: pc=0x%llx, o7=0x%llx, val=0x%llx\n",
2715 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
2716 break;
2717 case 0x05: /* pc */
2718 val = sp->pc; /* Use a macro - FIXME */
2719 if (v9p->pstate.addr_mask) val &= MASK64(31,0); /* FIXME: SV9_ID125 */
2720 break;
2721 case 0x06: /* fprs */
2722 /* Looks like that even if there is no FPU, we still need an FPRS register.
2723 * There doesn't seem to be scope even for emulation.
2724 */
2725
2726 val = ((v9p->fprs.fef) ? (1LL << V9_FPRS_FEF_BIT) :0LL) |
2727 (1LL << V9_FPRS_DU_BIT) | /* for now du & dl are always 1 if fef */
2728 (1LL << V9_FPRS_DL_BIT);
2729DBGFPRS( lprintf(sp->gid, "ss_read_state_reg: %%fprs=%x @ pc=0x%llx\n", val, sp->pc); );
2730 break;
2731
2732#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2733 case 0x10: /* PCR */
2734 if (v9p->state == V9_User) {
2735 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
2736 return;
2737 }
2738 val = nsp->pcr;
2739 DBGPIC( lprintf(sp->gid, "ss_read_state_reg: (rd %%pcr @ pc=0x%llx, val=0x%llx)\n",
2740 sp->pc, val); );
2741 nsp->pcr &= ~SS_PCR_CLEAR_ON_READ;
2742 break;
2743
2744 case 0x11: /* PIC */
2745 /*
2746 * Need to create a proper pic value containing [pic1][pic0] where each pic
2747 * is a 32bit number.
2748 *
2749 * pic0 needs to be a 32bit Instr count based on the sp->pic0 value
2750 * For now, pic1 can be anything as long as it's increasing
2751 */
2752 if (v9p->state == V9_User && (nsp->pcr & SS_PCR_PRIV) != 0) {
2753 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_action);
2754 return;
2755 }
2756 if (nsp->pcr & SS_PCR_UT_ST) {
2757 UPDATE_PIC(sp, nsp, v9p);
2758 }
2759
2760 val = PIC0_PIC1_TO_CPU_COUNTER(nsp->pic0, nsp->pic1);
2761 DBGPIC( lprintf(sp->gid, "ss_read_state_reg: rd %%pic @ pc=0x%llx, val=0x%llx [cycle=0x%llx]\n",
2762 sp->pc, val, sp->cycle); );
2763 break;
2764#endif /* } */
2765
2766 case 0x13:
2767#ifdef ROCK
2768 if (!nsp->fpae) {
2769 v9p->post_precise_trap(sp,
2770 Sparcv9_trap_illegal_instruction);
2771 return;
2772 }
2773#endif
2774 if (!v9p->fpu_on) {
2775 v9p->post_precise_trap(sp, Sparcv9_trap_fp_disabled);
2776 return;
2777 }
2778 val = sp->v9_gsr;
2779 break;
2780
2781 case 0x16: /* softint */
2782 if (v9p->state == V9_User) {
2783 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
2784 return;
2785 }
2786 val = ((v9p->stick_cmpr.pending) ? (1LL<<16) : 0LL) |
2787 v9p->softint |
2788 ((v9p->tick_cmpr.pending) ? 1LL : 0LL );
2789 break;
2790#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2791 case 0x17: /* tick_cmpr */
2792 if (v9p->state == V9_User) {
2793 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
2794 return;
2795 }
2796 val = ss_tick_cmpr_read(sp, &v9p->tick_cmpr);
2797 DBGTICKREAD( lprintf(sp->gid,
2798 "tick_cmpr read priv: pc=0x%llx, o7=0x%llx, val=0x%llx\n",
2799 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
2800 break;
2801#endif /* } */
2802 case 0x18: /* stick */
2803 if (v9p->state == V9_User && v9p->_stick.non_priv_trap) {
2804 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_action);
2805 return;
2806 }
2807 val = ss_read_stick(sp);
2808
2809#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2810 if (v9p->_stick.non_priv_trap) val |= 1ULL<<63;
2811#endif /* } */
2812 DBGTICKREAD( lprintf(sp->gid,
2813 "stick read priv: pc=0x%llx, o7=0x%llx, val=0x%llx\n",
2814 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
2815 break;
2816 case 0x19: /* stick_cmpr */
2817 if (v9p->state == V9_User) {
2818 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
2819 return;
2820 }
2821 val = ss_tick_cmpr_read(sp, &v9p->stick_cmpr);
2822 DBGTICKREAD( lprintf(sp->gid,
2823 "stick_cmpr read priv: pc=0x%llx, o7=0x%llx, val=0x%llx\n",
2824 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
2825 break;
2826#ifdef NIAGARA1
2827 case 0x1a: /* strand_sts_reg */
2828 switch (v9p->state) {
2829 case V9_User:
2830 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
2831 return;
2832 case V9_Priv:
2833 /* If a strand is reading it, it must be active... */
2834 val = THREAD_STS_ACTIVE;
2835 IMPL_WARNING(("ss_read_state_reg: (rd %%tsr @ pc=0x%llx) deprecated access to strand status register", sp->pc));
2836 break;
2837 case V9_HyperPriv:
2838 case V9_RED:
2839 {
2840 ss_proc_t *npp;
2841 uint_t i, ie;
2842
2843 npp = (ss_proc_t *)(sp->config_procp->procp);
2844 val = 0;
2845 i = nsp->core * STRANDSPERCORE;
2846 ie = i + STRANDSPERCORE;
2847 while (i < ie) {
2848 val <<= THREAD_STS_TSTATE_BITS;
2849 val |= npp->sfsm_state[i++];
2850 }
2851 val <<= THREAD_STS_TSTATE_SHIFT;
2852 val |= (nsp->vcore_id << THREAD_STS_SHIFT);
2853 if (nsp->spec_en)
2854 val |= THREAD_STS_SPEC_EN;
2855 val |= THREAD_STS_ACTIVE;
2856 }
2857 break;
2858 default:
2859 abort();
2860 }
2861 DBGCMP( lprintf(sp->gid,
2862 "%%tsr read: pc=0x%llx, o7=0x%llx, val=0x%llx\n",
2863 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
2864 break;
2865#endif
2866
2867#ifdef ROCK
2868 case 0x1c: /* cps */
2869 val = nsp->cps;
2870 DBGTM( lprintf(sp->gid, "%%cps read: "
2871 "pc=0x%llx, o7=0x%llx, val=0x%llx\n",
2872 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
2873 break;
2874#endif
2875
2876#if 0
2877 /* No unimplemented registers currently. */
2878 case 0x??:
2879 FIXME_WARNING(("ss_read_state_reg: (rd) Unimplemented register 0x%x @ pc=0x%llx", state_reg, sp->pc));
2880#endif
2881 default:
2882 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
2883 return;
2884 }
2885
2886 if (rdest != Reg_sparcv9_g0) sp->intreg[rdest] = val; /* Use a macro - FIXME */
2887
2888 NEXT_INSTN(sp);
2889}
2890
2891
2892
2893
2894
2895
2896static void ss_write_state_reg(simcpu_t * sp, uint_t state_reg, uint64_t val)
2897{
2898 sparcv9_cpu_t * v9p;
2899 ss_strand_t * nsp;
2900 bool_t prev_val;
2901
2902 v9p = (sparcv9_cpu_t *)(sp->specificp);
2903 nsp = (ss_strand_t *)v9p->impl_specificp;
2904
2905#ifdef ROCK
2906 if (TM_ACTIVE(nsp)) {
2907 EXEC_WARNING(("TM ERROR: TM active in 'ss_write_state_reg' function pc=0x%llx.", sp->pc));
2908 nsp->tm_fail(sp, V9_CPS_INSTR);
2909 return;
2910 }
2911#endif
2912
2913 switch (state_reg) {
2914 case 0x0: /* y */
2915#ifdef ROCK
2916 if (!nsp->fpae) {
2917 v9p->post_precise_trap(sp,
2918 Sparcv9_trap_illegal_instruction);
2919 return;
2920 }
2921#endif
2922 sp->v9_y = val & MASK64(31,0);
2923 break;
2924 case 0x2: /* ccr */
2925 sp->v9_ccr = val & V9_CCR_MASK;
2926 break;
2927 case 0x3: /* asi */
2928 sp->v9_asi = val & V9_ASI_MASK;
2929 break;
2930 case 0x4: /* tick */
2931#if defined(NIAGARA1) || defined(NIAGARA2)
2932 switch (v9p->state) {
2933 case V9_User:
2934 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
2935 return;
2936 case V9_Priv:
2937 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
2938 return;
2939 case V9_HyperPriv:
2940 case V9_RED:
2941 break;
2942 }
2943 /* On niagara stick is an alias for tick */
2944 ss_write_tick(sp, val);
2945 DBGTICK( lprintf(sp->gid,
2946 "tick write asr: pc=0x%llx, o7=0x%llx, val=0x%llx tick=0x%llx\n",
2947 sp->pc, sp->intreg[Reg_sparcv9_o7], val, ss_read_tick(sp)); );
2948 break;
2949#elif ROCK
2950 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
2951 return;
2952#else
2953#error "No valid processor defined."
2954#endif
2955 case 0x6: /* fprs */
2956 /* Looks like that even if there is no FPU, we still need an FPRS register.
2957 * There doesn't seem to be scope even for emulation.
2958 */
2959
2960 prev_val = v9p->fpu_on;
2961DBGFPRS( lprintf(sp->gid, "ss_write_state_reg: %%fprs=%x @ pc=0x%llx\n", val, sp->pc); );
2962 v9p->fprs.fef = ((val >> V9_FPRS_FEF_BIT)&0x1) ? true : false;
2963
2964 v9p->fpu_on = (v9p->pstate.fpu_enabled && v9p->fprs.fef && v9p->has_fpu);
2965#ifdef FP_DECODE_DISABLED
2966 /* if FPU was enabled, we may have just changed the behaviour of FP instns */
2967 /* in which case flush the decoded instruction cache */
2968 if (v9p->fpu_on != prev_val) {
2969 sp->xicache_instn_flush_pending = true;
2970 set_sync_pending(sp);
2971 }
2972#endif /* FP_DECODE_DISABLED */
2973
2974 v9p->fprs.du = ((val >> V9_FPRS_DU_BIT)&0x1) ? true : false;
2975 v9p->fprs.dl = ((val >> V9_FPRS_DL_BIT)&0x1) ? true : false;
2976 break;
2977
2978#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
2979 case 0x10: /* PCR */
2980 if (v9p->state == V9_User) {
2981 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
2982 return;
2983 }
2984 val &= SS_PCR_MASK;
2985 DBGPIC( lprintf(sp->gid, "ss_write_state_reg: "
2986 "(wr %%pcr @ pc=0x%llx, 0x%llx -> 0x%llx)\n",
2987 sp->pc, nsp->pcr, val); );
2988
2989 /*
2990 * If the pcr is active, we need to start counting instns
2991 * so that when the pic is read, it counts the number of
2992 * instns.
2993 * As soon as the pic starts counting, we need to catch
2994 * when it will overflow so that we can trigger a PIL 15 intr
2995 */
2996 if (val & SS_PCR_UT_ST) {
2997 /* Starting to count? Sample from now. */
2998 if ((nsp->pcr & SS_PCR_UT_ST) == 0)
2999 RESET_PIC_SAMPLE_BASES(sp, nsp, v9p);
3000 nsp->pcr = val;
3001 ss_recomp_cycle_target(sp); /* catch next overflow event */
3002 } else {
3003 /* Stopping counting? Collect last samples. */
3004 if ((nsp->pcr & SS_PCR_UT_ST) != 0)
3005 UPDATE_PIC(sp, nsp, v9p);
3006 nsp->pcr = val;
3007 }
3008
3009 if (SS_PCR_TEST_OVF_PENDING(nsp->pcr)) {
3010 v9p->softint |= BIT(15);
3011 DBGSOFTINT( lprintf(sp->gid,
3012 "softint wr pcr overflow: pc=0x%llx, o7=0x%llx, val=0x%llx, stick=%u, tick=%u\n",
3013 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->softint, v9p->stick_cmpr.pending,
3014 v9p->tick_cmpr.pending); );
3015 ss_check_interrupts(sp);
3016 }
3017 break;
3018
3019 case 0x11: /* PIC */
3020 if (v9p->state == V9_User && (nsp->pcr & SS_PCR_PRIV) != 0) {
3021 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_action);
3022 return;
3023 }
3024 DBGPIC( lprintf(sp->gid, "ss_write_state_reg: (wr %%pic @ pc=0x%llx, val=0x%llx)\n", sp->pc, val); );
3025 nsp->pic0 = CPU_COUNTER_TO_PIC0(val);
3026 nsp->pic1 = CPU_COUNTER_TO_PIC1(val);
3027 RESET_PIC_SAMPLE_BASES(sp, nsp, v9p);
3028 ss_recomp_cycle_target(sp); /* catch next overflow event */
3029
3030 break;
3031#endif /* } */
3032
3033 case 0x13: /* GSR */
3034#ifdef ROCK
3035 if (!nsp->fpae) {
3036 v9p->post_precise_trap(sp,
3037 Sparcv9_trap_illegal_instruction);
3038 return;
3039 }
3040#endif
3041 if (!v9p->fpu_on) {
3042 v9p->post_precise_trap(sp, Sparcv9_trap_fp_disabled);
3043 return;
3044 }
3045DBGFSR( lprintf(sp->gid, "ss_write_state_reg: pc=0x%llx, gsr=0x%llx (was 0x%llx)\n", sp->pc, val, sp->v9_gsr); );
3046 sp->v9_gsr = val & V9_GSR_REG_MASK;
3047 break;
3048
3049 case 0x14: /* set softint register */
3050 if (v9p->state == V9_User) {
3051 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3052 return;
3053 }
3054 if ((val>>16)&1LL) v9p->stick_cmpr.pending = true;
3055 if ((val>>0)&1LL) v9p->tick_cmpr.pending = true;
3056 v9p->softint |= val & MASK64(15,1);
3057 DBGSOFTINT( lprintf(sp->gid,
3058 "softint write set: pc=0x%llx, o7=0x%llx, val=0x%llx, "
3059 "softint=0x%llx, stick=%d, tick=%d\n",
3060 sp->pc, sp->intreg[Reg_sparcv9_o7], val, v9p->softint,
3061 v9p->stick_cmpr.pending, v9p->tick_cmpr.pending); );
3062 ss_check_interrupts(sp);
3063 break;
3064 case 0x15: /* clear softint register */
3065 if (v9p->state == V9_User) {
3066 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3067 return;
3068 }
3069 if ((val>>16)&1LL) v9p->stick_cmpr.pending = false;
3070 if ((val>>0)&1LL) v9p->tick_cmpr.pending = false;
3071 v9p->softint &= (~val) & MASK64(15,1);
3072 DBGSOFTINT( lprintf(sp->gid,
3073 "softint write clear: pc=0x%llx, o7=0x%llx, val=0x%llx, "
3074 "softint=0x%llx, stick=%d, tick=%d\n",
3075 sp->pc, sp->intreg[Reg_sparcv9_o7], val, v9p->softint,
3076 v9p->stick_cmpr.pending, v9p->tick_cmpr.pending); );
3077 ss_check_interrupts(sp);
3078 break;
3079 case 0x16: /* softint */
3080 if (v9p->state == V9_User) {
3081 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3082 return;
3083 }
3084 v9p->stick_cmpr.pending = ((val >> 16)&1LL) ? true : false;
3085 v9p->tick_cmpr.pending = ((val >> 0)&1LL) ? true : false;
3086 v9p->softint = val & MASK64(15,1);
3087 DBGSOFTINT( lprintf(sp->gid,
3088 "softint write: pc=0x%llx, o7=0x%llx, softint=0x%llx, "
3089 "stick=%d, tick=%d\n",
3090 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->softint,
3091 v9p->stick_cmpr.pending, v9p->tick_cmpr.pending); );
3092 ss_check_interrupts(sp);
3093 break;
3094#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3095 case 0x17: /* tick_cmpr */
3096 if (v9p->state == V9_User) {
3097 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3098 return;
3099 }
3100 ss_tick_cmpr_write(sp, &v9p->tick_cmpr, val);
3101 DBGTICK( lprintf(sp->gid,
3102 "tick_cmpr write: pc=0x%llx, o7=0x%llx, val=0x%llx inten=%u val-tick=0x%llx\n",
3103 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->tick_cmpr.compare, v9p->tick_cmpr.interrupt_enabled,
3104 v9p->tick_cmpr.compare - ss_read_tick(sp)); );
3105 ss_recomp_cycle_target(sp);
3106 break;
3107#endif /* } */
3108 case 0x18: /* stick */
3109#if defined(NIAGARA1) || defined(NIAGARA2)
3110 switch (v9p->state) {
3111 case V9_User:
3112 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3113 return;
3114 case V9_Priv:
3115 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3116 return;
3117 case V9_HyperPriv:
3118 case V9_RED:
3119 break;
3120 }
3121 ss_write_stick(sp, val);
3122 DBGTICK( lprintf(sp->gid,
3123 "stick write: pc=0x%llx, o7=0x%llx, val=0x%llx stick=0x%llx\n",
3124 sp->pc, sp->intreg[Reg_sparcv9_o7], val, ss_read_stick(sp)); );
3125 break;
3126#elif defined(ROCK)
3127 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3128 return;
3129#else
3130#error "No valid processor defined."
3131#endif
3132 case 0x19: /* stick_cmpr */
3133 if (v9p->state == V9_User) {
3134 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3135 return;
3136 }
3137 ss_tick_cmpr_write(sp, &v9p->stick_cmpr, val);
3138 DBGTICK( lprintf(sp->gid,
3139 "stick_cmpr write: pc=0x%llx, o7=0x%llx, val=0x%llx inten=%u val-stick=0x%llx\n",
3140 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->stick_cmpr.compare, v9p->stick_cmpr.interrupt_enabled,
3141 v9p->stick_cmpr.compare - ss_read_stick(sp)); );
3142 ss_recomp_cycle_target(sp);
3143 break;
3144#ifdef NIAGARA1
3145 case 0x1a: /* strand_sts_reg */
3146 switch (v9p->state) {
3147 case V9_User:
3148 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3149 return;
3150 case V9_Priv:
3151 DBGCMP( lprintf(sp->gid, "%%tsr write priv: "
3152 "pc=0x%llx, o7=0x%llx, val=0x%llx\n",
3153 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
3154 IMPL_WARNING(("ss_write_state_reg: (wr %%tsr @ pc=0x%llx) deprecated access to strand status register", sp->pc));
3155 goto thread_halt;
3156 case V9_HyperPriv:
3157 case V9_RED:
3158 DBGCMP( lprintf(sp->gid, "%%tsr write: "
3159 "pc=0x%llx, o7=0x%llx, val=0x%llx\n",
3160 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
3161 nsp->spec_en = BIT_TEST( val, THREAD_STS_SPEC_EN_BIT ) ? true : false;
3162thread_halt: if (!(val & THREAD_STS_ACTIVE)) {
3163 IMPL_WARNING(("ss_write_state_reg: (wr %%tsr @ pc=0x%llx) thread halt not supported", sp->pc));
3164 }
3165 break;
3166 default:
3167 abort();
3168 }
3169 break;
3170#endif
3171
3172#ifdef ROCK
3173 case 0x1c: /* cps */
3174 DBGTM( lprintf(sp->gid, "%%cps write: "
3175 "pc=0x%llx, o7=0x%llx, val=0x%llx\n",
3176 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
3177 nsp->cps = val & V9_CPS_REG_MASK;
3178 break;
3179#endif
3180
3181#if 0
3182 /* No unimplemented registers currently. */
3183 case 0x??:
3184 FIXME_WARNING(("ss_write_state_reg: (wr) Unimplemented register 0x%x @ pc=0x%llx", state_reg, sp->pc));
3185#endif
3186 default:
3187 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3188 return;
3189 }
3190
3191 NEXT_INSTN(sp);
3192}
3193
3194
3195
3196
3197static void ss_read_priv_reg(simcpu_t * sp, uint_t rdest, uint_t priv_reg)
3198{
3199 sparcv9_cpu_t * v9p;
3200 uint64_t val;
3201
3202 v9p = (sparcv9_cpu_t *)(sp->specificp);
3203
3204 ASSERT(0LL==sp->intreg[Reg_sparcv9_g0]);
3205
3206 if (v9p->state == V9_User) {
3207 ASSERT( !v9p->pstate.priv && !v9p->hpstate.hpriv );
3208 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3209 return;
3210 }
3211
3212 switch (priv_reg) {
3213 case 0: /* tpc */
3214 if (v9p->tl == 0) goto illegal_instruction;
3215 val = N_TPC(v9p, v9p->tl);
3216#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3217 VA48_ASSERT(val);
3218#endif /* } */
3219 if (v9p->pstate.addr_mask) {
3220 val &= MASK64(31,0); /* FIXME: SV9_ID125 */
3221 EXEC_WARNING(("@ pc=0x%llx : TPC read with pstate.am == 1", sp->pc));
3222 }
3223 break;
3224 case 1: /* tnpc */
3225 if (v9p->tl == 0) goto illegal_instruction;
3226 val = N_TNPC(v9p, v9p->tl);
3227#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3228 VA48_ASSERT(val);
3229#endif /* } */
3230 if (v9p->pstate.addr_mask) {
3231 val &= MASK64(31,0); /* FIXME: SV9_ID125 */
3232 EXEC_WARNING(("@ pc=0x%llx : TNPC read with pstate.am == 1", sp->pc));
3233 }
3234 break;
3235 case 2:
3236 if (v9p->tl == 0) goto illegal_instruction;
3237 val = N_TSTATE(v9p, v9p->tl);
3238 break;
3239 case 3:
3240 if (v9p->tl == 0) goto illegal_instruction;
3241 val = N_TT(v9p, v9p->tl);
3242 break;
3243 case 4: /* tick */
3244 val = ss_read_tick(sp);
3245
3246#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3247 if (v9p->_tick.non_priv_trap) val |= 1ULL<<63;
3248#endif /* } */
3249 DBGTICKREAD( lprintf(sp->gid,
3250 "tick read priv: pc=0x%llx, o7=0x%llx, val=0x%llx\n",
3251 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
3252 break;
3253 case 5: /* tba */
3254 val = v9p->tba;
3255 break;
3256 case 6: /* pstate */
3257 val = ss_read_pstate(v9p);
3258 break;
3259 case 7: /* tl */
3260 val = v9p->tl;
3261 break;
3262 case 8: /* pil */
3263 val = v9p->pil;
3264 break;
3265 case 9: /* cwp */
3266 val = v9p->cwp;
3267 break;
3268 case 0xa: /* cansave */
3269 val = v9p->cansave;
3270 break;
3271 case 0xb: /* canrestore */
3272 val = v9p->canrestore;
3273 break;
3274 case 0xc: /* cleanwin */
3275 val = v9p->cleanwin;
3276 break;
3277 case 0xd: /* otherwin */
3278 val = v9p->otherwin;
3279 break;
3280 case 0xe:
3281 val = (v9p->wstate_normal << V9_WSTATE_NORMAL_BITS) |
3282 (v9p->wstate_other << V9_WSTATE_OTHER_BITS);
3283 break;
3284 case 0x10:
3285 val = v9p->gl;
3286 break;
3287 default:
3288illegal_instruction:
3289 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3290 return;
3291 }
3292
3293 if (rdest != Reg_sparcv9_g0) sp->intreg[rdest] = val;
3294
3295 NEXT_INSTN(sp);
3296}
3297
3298
3299
3300static void ss_write_priv_reg(simcpu_t * sp, uint_t priv_reg, uint64_t val)
3301{
3302 sparcv9_cpu_t * v9p = (sparcv9_cpu_t *)(sp->specificp);
3303 uint64_t old_val;
3304 ss_strand_t * nsp = (ss_strand_t *)(v9p->impl_specificp);
3305
3306 ASSERT(0LL==sp->intreg[Reg_sparcv9_g0]);
3307
3308 if (v9p->state == V9_User) {
3309 ASSERT( !v9p->pstate.priv && !v9p->hpstate.hpriv );
3310 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3311 return;
3312 }
3313
3314
3315#ifdef ROCK
3316 if (TM_ACTIVE(nsp)) {
3317 EXEC_WARNING(("TM ERROR: TM active in 'ss_write_priv_reg' function pc=0x%llx.", sp->pc));
3318 nsp->tm_fail(sp, V9_CPS_INSTR);
3319 return;
3320 }
3321#endif
3322
3323 switch (priv_reg) {
3324 case 0: /* tpc */
3325 if (v9p->tl == 0) goto illegal_instruction;
3326 if (v9p->pstate.addr_mask) EXEC_WARNING(("writing to tpc with pstate.am=1"));
3327 val &= ~3;
3328#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3329 val = VA48(val);
3330#endif /* } */
3331 N_TPC(v9p, v9p->tl) = val; /* FIXME: SV9_ID125 issue ? */
3332 break;
3333 case 1: /* tnpc */
3334 if (v9p->tl == 0) goto illegal_instruction;
3335 if (v9p->pstate.addr_mask) EXEC_WARNING(("writing to tnpc with pstate.am=1"));
3336 val &= ~3;
3337#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3338 val = VA48(val);
3339#endif /* } */
3340 N_TNPC(v9p, v9p->tl) = val; /* FIXME: SV9_ID125 issue ? */
3341 break;
3342 case 2: /* tstate */
3343 if (v9p->tl == 0) goto illegal_instruction;
3344 N_TSTATE(v9p, v9p->tl) = val &
3345 ((V9_TSTATE_GL_MASK<<V9_TSTATE_GL_SHIFT) |
3346 (V9_TSTATE_CCR_MASK<<V9_TSTATE_CCR_SHIFT) |
3347 (V9_TSTATE_ASI_MASK<<V9_TSTATE_ASI_SHIFT) |
3348 (V9_TSTATE_PSTATE_MASK<<V9_TSTATE_PSTATE_SHIFT) |
3349 (V9_TSTATE_CWP_MASK<<V9_TSTATE_CWP_SHIFT) );
3350 break;
3351 case 3: /* tt */
3352 if (v9p->tl == 0) goto illegal_instruction;
3353DBGTSTACK(
3354 log_lock();
3355 log_printf(sp->gid, "Pre-TT write pc=0x%llx\n", sp->pc);
3356 sparcv9_dump_state(sp); );
3357 if ((val & V9_TT_MASK) != N_TT(v9p, v9p->tl)) {
3358 N_TT(v9p, v9p->tl) = val & V9_TT_MASK;
3359DBGTSTACK(log_printf(sp->gid, "Post-TT write\n"); sparcv9_dump_state(sp););
3360 } else {
3361DBGTSTACK(log_printf(sp->gid, "Post-TT write - TT unchanged\n"););
3362 }
3363DBGTSTACK( log_unlock(); );
3364 break;
3365 case 0x4: /* tick */
3366#if defined(NIAGARA1) || defined(NIAGARA2)
3367 switch (v9p->state) {
3368 default:
3369 case V9_Priv:
3370 goto illegal_instruction;
3371 case V9_HyperPriv:
3372 case V9_RED:
3373 break;
3374 }
3375 /* On niagara stick is an alias for tick */
3376 ss_write_tick(sp, val);
3377 DBGTICK( lprintf(sp->gid,
3378 "tick write priv: pc=0x%llx, o7=0x%llx, val=0x%llx tick=0x%llx\n",
3379 sp->pc, sp->intreg[Reg_sparcv9_o7], val, ss_read_tick(sp)); );
3380 break;
3381#elif ROCK
3382 goto illegal_instruction;
3383#else
3384#error "No valid processor defined."
3385#endif
3386 case 5: /* tba */
3387#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3388 val = VA48(val);
3389#endif /* } */
3390 v9p->tba = val & V9_TBA_MASK;
3391 break;
3392 case 6: /* pstate */
3393 ss_write_pstate(sp, val); /* like to change states */
3394 break; /* pc updated as usual */
3395 case 7: /* tl - saturates */
3396 if (v9p->state == V9_Priv) {
3397 if (val > Q_MAXPTL) {
3398 EXEC_WARNING(("privileged write to %%tl of %u saturated to %u (%%pc=0x%llx)", val, Q_MAXPTL, sp->pc));
3399 val = Q_MAXPTL;
3400 }
3401#if DEBUG_TL_RAISE
3402 /* Unsafe raising of %tl, trash values */
3403 if (val > v9p->tl) {
3404 /* bogus values must pass the VA48_ASSERT */
3405 N_TPC(v9p, val) = 0xffffbeefdeadbeecull;
3406 N_TNPC(v9p, val) = 0xffffbeefdeadbeecull;
3407 N_TSTATE(v9p, val) =
3408 ((V9_TSTATE_GL_MASK<<V9_TSTATE_GL_SHIFT) |
3409 (V9_TSTATE_CCR_MASK<<V9_TSTATE_CCR_SHIFT) |
3410 (V9_TSTATE_ASI_MASK<<V9_TSTATE_ASI_SHIFT) |
3411 (V9_TSTATE_PSTATE_MASK<<V9_TSTATE_PSTATE_SHIFT) |
3412 (V9_TSTATE_CWP_MASK<<V9_TSTATE_CWP_SHIFT) );
3413 N_TT(v9p, val) = 0xffff & V9_TT_MASK;
3414 }
3415#endif /* DEBUG_TL_RAISE */
3416 v9p->tl = val;
3417 } else {
3418 if (val > v9p->maxtl) {
3419 EXEC_WARNING(("hyperprivileged write to %%tl of %u saturated to %u (%%pc=0x%llx)", val, v9p->maxtl, sp->pc));
3420 }
3421 v9p->tl = (val>v9p->maxtl) ? v9p->maxtl : val;
3422 }
3423 xcache_set_tagstate(sp);
3424 break;
3425 case 8: /* pil */
3426 v9p->pil = val & V9_PIL_MASK;
3427 ss_check_interrupts(sp);
3428 break;
3429 case 9: /* cwp - saturates */
3430 old_val = val;
3431 val &= v9p->nwins_mask;
3432 if (val >= v9p->nwins) {
3433 val = (v9p->nwins - 1);
3434#if 0 /* this is expected */
3435 EXEC_WARNING(("write to %%cwp of %u saturated to %u (%%pc=0x%llx)",
3436 old_val, val , sp->pc));
3437#endif
3438 }
3439 if (v9p->cwp != val) {
3440 v9p->cwp = val;
3441 sparcv9_active_window(sp, v9p->cwp);
3442 }
3443 break;
3444 case 10: /* cansave - saturates */
3445 old_val = val;
3446 val &= v9p->nwins_mask;
3447 if (val >= v9p->nwins) {
3448 val = (v9p->nwins - 1);
3449 EXEC_WARNING(("write to %%cansave of %u saturated to %u (%%pc=0x%llx)",
3450 old_val, val, sp->pc));
3451 }
3452 v9p->cansave = val;
3453 break;
3454 case 11: /* canrestore - saturates */
3455 old_val = val;
3456 val &= v9p->nwins_mask;
3457 if (val >= v9p->nwins) {
3458 val = (v9p->nwins - 1);
3459 EXEC_WARNING(("write to %%canrestore of %u saturated to %u (%%pc=0x%llx)",
3460 old_val, val, sp->pc));
3461 }
3462 v9p->canrestore = val;
3463 break;
3464 case 12: /* cleanwin - saturates */
3465 old_val = val;
3466 val &= v9p->nwins_mask;
3467 if (val >= v9p->nwins) {
3468 val = (v9p->nwins - 1);
3469 EXEC_WARNING(("write to %%cleanwin of %u saturated to %u(%%pc=0x%llx)",
3470 old_val, val, sp->pc));
3471 }
3472 v9p->cleanwin = val;
3473 break;
3474 case 13: /* otherwin - saturates */
3475 old_val = val;
3476 val &= v9p->nwins_mask;
3477 if (val >= v9p->nwins) {
3478 val = (v9p->nwins - 1);
3479 EXEC_WARNING(("write to %%otherwin of %u saturated to %u (%%pc=0x%llx)",
3480 old_val, val, sp->pc));
3481 }
3482 v9p->otherwin = val;
3483 break;
3484 case 14: /* wstate */
3485 v9p->wstate_normal = (val >> V9_WSTATE_NORMAL_BITS) & V9_WSTATE_MASK;
3486 v9p->wstate_other = (val >> V9_WSTATE_OTHER_BITS) & V9_WSTATE_MASK;
3487 break;
3488 case 16:
3489 switch(v9p->state) {
3490 default:
3491 case V9_User: abort(); /* shouldn't get here */
3492 case V9_Priv:
3493 if (val > Q_MAXPGL) {
3494 EXEC_WARNING(("privileged write to %%gl of %u saturated to %u (%%pc=0x%llx)", val, Q_MAXPGL, sp->pc));
3495 val = Q_MAXPGL;
3496 }
3497 break;
3498 case V9_HyperPriv:
3499 case V9_RED:
3500 if (val >= v9p->nglobals) {
3501 EXEC_WARNING(("hyperprivileged write to %%gl of %u saturated to %u (%%pc=0x%llx)", val, v9p->nglobals - 1, sp->pc));
3502 val = v9p->nglobals-1;
3503 }
3504 break;
3505 }
3506#if DEBUG_GL_RAISE
3507 /* Unsafe raising of %gl, trash values */
3508 if (v9p->state == V9_Priv && val > v9p->gl) {
3509 uint_t j, i;
3510 uint64_t *arch_regp;
3511
3512 for (j = val; j > v9p->gl; j--) {
3513 arch_regp = &(v9p->globalsp[(val)*V9_GLOBAL_GROUP]);
3514 arch_regp++; /* skip %g0 */
3515 for (i = V9_GLOBAL_GROUP - 1; i > 0;i-- ) {
3516 *arch_regp++ = 0xdeadbeefdeadbeefull;
3517 }
3518 }
3519 }
3520#endif /* DEBUG_GL_RAISE */
3521 if (v9p->gl != val) {
3522 v9p->gl = val;
3523 sparcv9_active_globals(sp, v9p->gl);
3524 }
3525 break;
3526
3527 default:
3528illegal_instruction:
3529 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3530 return;
3531 }
3532
3533 NEXT_INSTN(sp);
3534}
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545static void ss_read_hyp_priv_reg(simcpu_t * sp, uint_t rdest, uint_t priv_reg)
3546{
3547 sparcv9_cpu_t * v9p;
3548 uint64_t val;
3549 ss_strand_t * nsp;
3550
3551 v9p = (sparcv9_cpu_t *)(sp->specificp);
3552 nsp = v9p->impl_specificp;
3553
3554 if (V9_HyperPriv!=v9p->state && V9_RED!=v9p->state) {
3555 ASSERT( !v9p->hpstate.hpriv );
3556 goto illegal_instruction;
3557 }
3558
3559 switch (priv_reg) {
3560 case 0x0: /* hpstate */
3561 val = ss_read_hpstate(v9p);
3562 break;
3563 case 0x1: /* htstate */
3564 if (v9p->tl == 0) goto illegal_instruction;
3565 val = N_HTSTATE(v9p, v9p->tl);
3566 break;
3567 case 0x3:
3568 val = v9p->hstick_cmpr.pending ? 1 : 0;
3569 break;
3570 case 0x5: /* htba */
3571 val = v9p->htba;
3572 break;
3573#if !defined(ROCK)
3574 case 0x6: /* hver */
3575 val = v9p->ver;
3576 break;
3577#endif
3578
3579#ifdef NIAGARA2 /* { */
3580 case 0x1e: /* halt */
3581 val = 0;
3582 IMPL_WARNING(("ss_read_hyp_priv_reg: (rdhpr %%halt, <reg> @ pc=0x%llx) halt not implemented", sp->pc));
3583 break;
3584#endif /* } */
3585#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3586 case 0x1f: /* hstick_cmpr */
3587 val = ss_tick_cmpr_read(sp, &v9p->hstick_cmpr);
3588 DBGTICKREAD( lprintf(sp->gid,
3589 "hstick_cmpr read: pc=0x%llx, o7=0x%llx, val=0x%llx\n",
3590 sp->pc, sp->intreg[Reg_sparcv9_o7], val); );
3591 break;
3592#endif /* } */
3593 default:
3594illegal_instruction:
3595 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3596 return;
3597 }
3598
3599 if (rdest != Reg_sparcv9_g0) sp->intreg[rdest] = val;
3600
3601 NEXT_INSTN(sp);
3602}
3603
3604
3605static void ss_write_hyp_priv_reg(simcpu_t * sp, uint_t priv_reg, uint64_t val)
3606{
3607 sparcv9_cpu_t * v9p;
3608 ss_strand_t * nsp;
3609
3610 v9p = (sparcv9_cpu_t *)(sp->specificp);
3611 nsp = v9p->impl_specificp;
3612
3613 if (V9_HyperPriv!=v9p->state && V9_RED!=v9p->state) {
3614 ASSERT( !v9p->hpstate.hpriv );
3615 goto illegal_instruction;
3616 }
3617
3618#ifdef ROCK
3619 if (TM_ACTIVE(nsp)) {
3620 EXEC_WARNING(("TM ERROR: TM active in 'ss_write_hyp_priv_reg' function pc=0x%llx.", sp->pc));
3621 nsp->tm_fail(sp, V9_CPS_INSTR);
3622 return;
3623 }
3624#endif
3625
3626 switch (priv_reg) {
3627 case 0x0: /* hpstate */
3628 ss_write_hpstate(sp, false, val);
3629 break;
3630 case 0x1: /* htstate */
3631 if (v9p->tl == 0) goto illegal_instruction;
3632#if defined(NIAGARA1)
3633#define SS_HTSTATE_MASK 0x0425
3634#elif defined(NIAGARA2)
3635#define SS_HTSTATE_MASK 0x0425
3636#elif defined(ROCK)
3637#define SS_HTSTATE_MASK 0xf025
3638#else
3639#error "No processor defined"
3640#endif
3641 N_HTSTATE(v9p, v9p->tl) = val & SS_HTSTATE_MASK;
3642 break;
3643 case 0x3:
3644 if (val & 1) {
3645 v9p->hstick_cmpr.pending = 1;
3646 ss_check_interrupts(sp);
3647 } else
3648 v9p->hstick_cmpr.pending = 0;
3649 DBGSOFTINT( lprintf(sp->gid,
3650 "hintp write: pc=0x%llx, o7=0x%llx, hintp=%u\n",
3651 sp->pc, sp->intreg[Reg_sparcv9_o7],
3652 v9p->hstick_cmpr.pending); );
3653 break;
3654 case 0x5: /* htba */
3655#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3656 val = VA48(val);
3657#endif /* } */
3658 v9p->htba = val & V9_HTBA_MASK;
3659 break;
3660 case 0x6: /* ver */
3661 /* read only register ! */
3662 goto illegal_instruction;
3663
3664#ifdef NIAGARA2 /* { */
3665 case 0x1e: /* halt */
3666 IMPL_WARNING(("ss_write_hyp_priv_reg: (wrhpr <reg>, %%halt @ pc=0x%llx) halt not implemented", sp->pc));
3667 break;
3668#endif /* } */
3669#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
3670 case 0x1f: /* hstick_cmpr */
3671 ss_tick_cmpr_write(sp, &v9p->hstick_cmpr, val);
3672 DBGTICK( lprintf(sp->gid,
3673 "hstick_cmpr write: pc=0x%llx, o7=0x%llx, val=0x%llx inten=%u val-stick=0x%llx\n",
3674 sp->pc, sp->intreg[Reg_sparcv9_o7], v9p->hstick_cmpr.compare, v9p->hstick_cmpr.interrupt_enabled,
3675 v9p->hstick_cmpr.compare - ss_read_stick(sp)); );
3676 ss_recomp_cycle_target(sp);
3677 break;
3678#endif /* } */
3679 default:
3680illegal_instruction:
3681 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3682 return;
3683 }
3684
3685 NEXT_INSTN(sp);
3686}
3687
3688
3689
3690 /*************************************************************/
3691
3692 /*
3693 * Done / Retry handler
3694 */
3695
3696void ss_done_retry(simcpu_t * sp, bool_t is_done)
3697{
3698 sparcv9_cpu_t * v9p;
3699 uint64_t val;
3700 uint_t win, gl;
3701 tvaddr_t new_pc, new_npc;
3702
3703 v9p = (sparcv9_cpu_t *)(sp->specificp);
3704
3705 if (v9p->state == V9_User) {
3706 v9p->post_precise_trap(sp, Sparcv9_trap_privileged_opcode);
3707 return;
3708 }
3709
3710 if (v9p->tl == 0) {
3711 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3712 return;
3713 }
3714
3715 if (!is_done) {
3716 new_pc = N_TPC(v9p, v9p->tl); /* retry */
3717 new_npc = N_TNPC(v9p, v9p->tl);
3718 } else {
3719 new_pc = N_TNPC(v9p, v9p->tl); /* done */
3720 new_npc = new_pc + 4;
3721 }
3722
3723 val = N_TSTATE(v9p, v9p->tl);
3724
3725DBGE( lprintf(sp->gid, "%s: tl=%u : gl=%u : pc=0x%llx : new_pc=0x%llx "
3726 "new_npc=0x%llx tstate=0x%llx\n",
3727 (is_done ? "done" : "retry"),
3728 v9p->tl, v9p->gl, sp->pc, new_pc, new_npc, val); );
3729
3730 /* Check for return to 32bit mode */
3731 if (((val >> V9_TSTATE_PSTATE_SHIFT) >> V9_PSTATE_AM_BIT)&1) {
3732 /* simple sanity checks ... */
3733 if (new_pc & MASK64(63,32)) EXEC_WARNING(("done/retry to non-32bit PC with pstate.am =1"));
3734 if (new_npc & MASK64(63,32)) EXEC_WARNING(("done/retry to non-32bit NPC with pstate.am =1"));
3735
3736 new_pc &= MASK64(31,0);
3737 new_npc &= MASK64(31,0);
3738 }
3739
3740 /* setup the new pc and npc */
3741 sp->pc = new_pc;
3742 sp->npc = new_npc;
3743
3744 /* restore everything from TSTATE register */
3745
3746 sp->v9_ccr = (val >> V9_TSTATE_CCR_SHIFT) & V9_TSTATE_CCR_MASK;
3747 sp->v9_asi = (val >> V9_TSTATE_ASI_SHIFT) & V9_TSTATE_ASI_MASK;
3748
3749 win = (val >> V9_TSTATE_CWP_SHIFT) & V9_TSTATE_CWP_MASK;
3750 if (win >= v9p->nwins) {
3751 warning("restoring cwp with value too large from TSTATE (%u) ; saturating",win);
3752 win = v9p->nwins-1;
3753 }
3754 if (v9p->cwp != win) {
3755 v9p->cwp = win;
3756 sparcv9_active_window(sp, v9p->cwp);
3757 }
3758
3759 gl = (val >> V9_TSTATE_GL_SHIFT) & V9_TSTATE_GL_MASK;
3760 switch(v9p->state) {
3761 default:
3762 case V9_User: abort(); /* shouldn't get here */
3763 case V9_Priv:
3764 if (gl > Q_MAXPGL) {
3765 EXEC_WARNING(("Restoring gl with value too large from TSTATE (%u) ; saturating to %u", gl, Q_MAXPGL));
3766 gl = Q_MAXPGL;
3767 }
3768 break;
3769 case V9_HyperPriv:
3770 case V9_RED:
3771 if (gl >= v9p->nglobals) {
3772 EXEC_WARNING(("Restoring gl with value too large from TSTATE (%u) ; saturating to %u", gl, v9p->nglobals-1));
3773 gl = v9p->nglobals-1;
3774 }
3775 break;
3776 }
3777 if (v9p->gl != gl) {
3778 v9p->gl = gl;
3779 sparcv9_active_globals(sp, v9p->gl);
3780 }
3781
3782 ss_write_pstate( sp, (val >> V9_TSTATE_PSTATE_SHIFT) & V9_TSTATE_PSTATE_MASK );
3783
3784#ifdef NIAGARA1
3785 /* FIXME: care not to overwrite the ENB bit in HPSTATE if we ever implement it */
3786#endif /* NIAGARA1 */
3787 ss_write_hpstate( sp, true, N_HTSTATE(v9p, v9p->tl) );
3788
3789 v9p->tl --;
3790 xcache_set_tagstate(sp);
3791}
3792
3793
3794 /*************************************************************/
3795
3796 /*
3797 * jpriv handler
3798 */
3799
3800void ss_jpriv(simcpu_t * sp, tvaddr_t addr)
3801{
3802 sparcv9_cpu_t * v9p;
3803 ss_strand_t * nsp;
3804
3805 v9p = (sparcv9_cpu_t *)(sp->specificp);
3806 nsp = v9p->impl_specificp;
3807
3808 if (v9p->state != V9_HyperPriv) {
3809 v9p->post_precise_trap(sp, Sparcv9_trap_illegal_instruction);
3810 return;
3811 }
3812
3813 if ((addr & 3) != 0) {
3814 v9p->post_precise_trap(sp, Sparcv9_trap_mem_address_not_aligned);
3815 return;
3816 }
3817
3818 /* setup the new pc and npc */
3819 sp->pc = addr;
3820 sp->npc = addr + 4;
3821
3822 /* clear HPSTATE.hpriv */
3823 v9p->hpstate.hpriv = false;
3824
3825 /* set PSTATE.priv */
3826 v9p->pstate.priv = true;
3827
3828 V9_STATE_CHANGE(sp, v9p, V9_Priv);
3829 sp->xicache_trans_flush_pending = true;
3830 sp->xdcache_trans_flush_pending = true;
3831 ss_check_interrupts(sp); /* because of state change */
3832
3833 /* ROCK PRM 1.2 (wip) does not specify PSTATE.AM behavior for jpriv */
3834}
3835
3836
3837 /*************************************************************/
3838
3839
3840 /*
3841 * Exception handling - very processor specific ...
3842 */
3843
3844
3845
3846
3847 /*
3848 * This function supports all synchronous and asynchronous traps
3849 * The result is to leave the cpu in the correct state ready
3850 * for trap execution.
3851 * This model supports only the new v9 trap gl globals
3852 * and of course the privileged, hyperpriv trap modes.
3853 */
3854
3855
3856
3857void ss_take_exception(simcpu_t * sp)
3858{
3859 sparcv9_cpu_t * v9p;
3860 sparcv9_state_t new_state;
3861 ss_strand_t * nsp;
3862 ss_proc_t * npp;
3863 ss_trap_type_t RED_tt = 0;
3864 bool_t prev_state;
3865 uint_t tl, oldtl;
3866 ss_trap_type_t tt; /* the trap we deliver */
3867 ss_trap_type_t actual_tt; /* the trap that occurred */
3868 tvaddr_t new_trap_pc;
3869
3870 v9p = (sparcv9_cpu_t *)(sp->specificp);
3871 nsp = v9p->impl_specificp;
3872 npp = (ss_proc_t *)(sp->config_procp->procp);
3873
3874 ASSERT(0LL==sp->intreg[Reg_sparcv9_g0]);
3875
3876 /*
3877 * OK, let's figure out which trap we need to take -
3878 * based on the list that is pending, and the
3879 * outstanding disrupting trap events.
3880 */
3881
3882 actual_tt = nsp->pending_precise_tt;
3883
3884 /*
3885 * anything precise will get generated by re-execution of the
3886 * same code sequence - so clear immediately
3887 */
3888 nsp->pending_precise_tt = SS_trap_NONE;
3889
3890 if (SS_trap_NONE != nsp->pending_async_tt) {
3891
3892 tt = nsp->pending_async_tt;
3893
3894 /* NB larger priority number = lower priority */
3895 if ( SS_trap_NONE == actual_tt || ss_trap_list[actual_tt].priority > ss_trap_list[tt].priority) {
3896 actual_tt = tt;
3897
3898 /* Only clear if we already detected it was not clear
3899 * and we took the trap
3900 */
3901 nsp->pending_async_tt = SS_trap_NONE;
3902 }
3903 }
3904
3905 /* More tests here - FIXME */
3906
3907 /*
3908 * Clear the global pending notice .. if nothing left pending.
3909 *
3910 * Note this could be simpler since above pending_precise_tt
3911 * is always set to SS_trap_NONE and pending_async_tt is
3912 * aleady being tested for SS_trap_NONE.
3913 */
3914
3915 if (SS_trap_NONE == nsp->pending_async_tt &&
3916 SS_trap_NONE == nsp->pending_precise_tt) {
3917
3918 sp->exception_pending = false;
3919 }
3920
3921 /* Bail if we found nothing to do ! error ? - FIXME */
3922 if (actual_tt == SS_trap_NONE) {
3923DBGE( lprintf(sp->gid, "No exception?\n"); );
3924 return;
3925 }
3926
3927
3928DBGE( if (v9p->tl != v9p->gl) {
3929 lprintf(sp->gid, "tl != gl: exception 0x%02x : %s : tl=%u : gl=%u : pc=0x%llx\n",
3930 actual_tt, ss_trap_list[actual_tt].trap_namep,
3931 v9p->tl, v9p->gl, sp->pc);
3932 } );
3933
3934#if RELINQUISH_QUANTUM_HACKS /* { */
3935 if (actual_tt == SS_trap_htrap_instruction &&
3936 sp->etp->nsimcpus > 1 &&
3937 sp->intreg[Reg_sparcv9_o5] == 0x12) {
3938 /* CPU yield hcall - yield this CPU's quantum */
3939 set_sync_pending(sp);
3940 }
3941#endif /* } */
3942
3943DBGE( lprintf(sp->gid, "Taking exception 0x%02x : %s : tl=%u : gl=%u : pc=0x%llx, npc=0x%llx\n",
3944 actual_tt, ss_trap_list[actual_tt].trap_namep,
3945 v9p->tl, v9p->gl, sp->pc, sp->npc); );
3946DBGHC( if (actual_tt >= SS_trap_htrap_instruction && v9p->state == V9_Priv)
3947 if (actual_tt == SS_trap_htrap_instruction)
3948 lprintf(sp->gid, "hcall fast:"
3949 " (%%o5=0x%llx)(0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx)"
3950 " [pc=0x%llx %%o6=0x%llx %%o7=0x%llx]\n",
3951 sp->intreg[Reg_sparcv9_o5],
3952 sp->intreg[Reg_sparcv9_o0],
3953 sp->intreg[Reg_sparcv9_o1],
3954 sp->intreg[Reg_sparcv9_o2],
3955 sp->intreg[Reg_sparcv9_o3],
3956 sp->intreg[Reg_sparcv9_o4],
3957 sp->pc,
3958 sp->intreg[Reg_sparcv9_o6],
3959 sp->intreg[Reg_sparcv9_o7]);
3960 else
3961 lprintf(sp->gid, "hcall hyper-fast:"
3962 " (TT=0x%03x)"
3963 "(0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx)"
3964 " [pc=0x%llx %%o6=0x%llx %%o7=0x%llx]\n",
3965 actual_tt,
3966 sp->intreg[Reg_sparcv9_o0],
3967 sp->intreg[Reg_sparcv9_o1],
3968 sp->intreg[Reg_sparcv9_o2],
3969 sp->intreg[Reg_sparcv9_o3],
3970 sp->intreg[Reg_sparcv9_o4],
3971 sp->intreg[Reg_sparcv9_o5],
3972 sp->pc,
3973 sp->intreg[Reg_sparcv9_o6],
3974 sp->intreg[Reg_sparcv9_o7]); );
3975
3976
3977 switch (actual_tt) {
3978
3979 /*
3980 * We special case the early reset traps that get special
3981 * behaviour and need to use the reset trap vector.
3982 */
3983 case SS_trap_power_on_reset:
3984 case SS_trap_watchdog_reset:
3985 case SS_trap_externally_initiated_reset:
3986 case SS_trap_software_initiated_reset:
3987#if defined(NIAGARA1) || defined(NIAGARA2)
3988 case SS_trap_RED_state_exception:
3989#endif
3990 ss_reset_trap(sp, actual_tt);
3991 return;
3992
3993#ifdef NIAGARA2
3994 case N2_trap_control_word_queue_interrupt:
3995 case N2_trap_modular_arithmetic_interrupt:
3996 break;
3997
3998 /*
3999 * FIXME: for now assert on traps that are not implemented yet
4000 */
4001 case SS_trap_control_transfer_instruction:
4002 case SS_trap_instruction_VA_watchpoint:
4003 case SS_trap_instruction_breakpoint:
4004 EXEC_WARNING(("Legion should not generate an unimplemented trap (TT=0x%x)",actual_tt));
4005 ASSERT(0);
4006#endif
4007
4008#ifdef ROCK
4009 case RK_trap_hyperprivileged_queue_0:
4010 case RK_trap_hyperprivileged_queue_1:
4011#endif
4012 case SS_trap_cpu_mondo_trap:
4013 case SS_trap_dev_mondo_trap:
4014 case SS_trap_resumable_error:
4015DBGMONDO( lprintf(sp->gid, "Mondo trap 0x%02x : %s : "
4016 "pc=0x%llx, npc=0x%llx\n",
4017 actual_tt, ss_trap_list[actual_tt].trap_namep,
4018 sp->pc, sp->npc); );
4019 break;
4020
4021 default:
4022 break;
4023 }
4024
4025
4026
4027 /* save the state of the
4028 * strand as the trap occurred.
4029 */
4030
4031 oldtl = v9p->tl;
4032 ASSERT(oldtl <= v9p->maxtl);
4033
4034 if (oldtl == v9p->maxtl) {
4035 RED_tt = SS_trap_watchdog_reset;
4036 } else {
4037 v9p->tl++;
4038 if (v9p->tl == v9p->maxtl)
4039 RED_tt = SS_trap_RED_state_exception;
4040 }
4041 tl = v9p->tl;
4042
4043 ASSERT(tl!=0);
4044
4045 if (v9p->pstate.addr_mask) {
4046 N_TPC( v9p, tl ) = sp->pc & MASK64(31,0);
4047 N_TNPC( v9p, tl ) = sp->npc & MASK64(31,0);
4048 } else {
4049 N_TPC( v9p, tl ) = sp->pc;
4050 N_TNPC( v9p, tl ) = sp->npc;
4051 }
4052
4053 ASSERT(actual_tt<SS_trap_illegal_value);
4054 N_TT( v9p, tl ) = actual_tt;
4055
4056 /* assemble tstate */
4057 N_TSTATE( v9p, tl ) =
4058 ((v9p->gl & V9_TSTATE_GL_MASK)<<V9_TSTATE_GL_SHIFT) |
4059 ((sp->v9_ccr & V9_TSTATE_CCR_MASK)<<V9_TSTATE_CCR_SHIFT) |
4060 ((sp->v9_asi & V9_TSTATE_ASI_MASK)<<V9_TSTATE_ASI_SHIFT) |
4061 (ss_read_pstate(v9p)<<V9_TSTATE_PSTATE_SHIFT) |
4062 ((v9p->cwp & V9_TSTATE_CWP_MASK)<<V9_TSTATE_CWP_SHIFT);
4063
4064 N_HTSTATE( v9p, tl ) = ss_read_hpstate(v9p);
4065
4066DBGTSTACK(
4067 log_lock();
4068 log_printf(sp->gid, "Precise trap\n");
4069 sparcv9_dump_state(sp);
4070 log_unlock(); );
4071
4072 /* Now for window traps there are some window reg adjustments
4073 * to be made here ...
4074 */
4075
4076 /* Modify cwp for window traps. */
4077 /* Even for hypervisor versions ? */
4078
4079 if (actual_tt == SS_trap_clean_window) {
4080 /* Increment cwp */
4081 v9p->cwp = INC_MOD(v9p->cwp, v9p->nwins);
4082 sparcv9_active_window(sp, v9p->cwp);
4083 } else
4084 if ( actual_tt>= SS_trap_spill_0_normal && actual_tt< (SS_trap_spill_7_other+3)) {
4085 /* Increment cwp by 2+CANSAVE */
4086 v9p->cwp = (v9p->cwp + 2 + v9p->cansave) % v9p->nwins;
4087 sparcv9_active_window(sp, v9p->cwp);
4088 } else
4089 if ( actual_tt>= SS_trap_fill_0_normal && actual_tt<=(SS_trap_fill_7_other+3)) {
4090 /* Decrement cwp */
4091 v9p->cwp = (v9p->cwp + v9p->nwins-1) % v9p->nwins;
4092 sparcv9_active_window(sp, v9p->cwp);
4093 }
4094
4095 tt = actual_tt; /* common case */
4096
4097 /*
4098 * First step is to handle all those operation common to trap setup
4099 */
4100
4101 prev_state = v9p->fpu_on;
4102 v9p->pstate.fpu_enabled = v9p->has_fpu;
4103 v9p->fpu_on = (v9p->fprs.fef && v9p->has_fpu);
4104#ifdef FP_DECODE_DISABLED
4105 /* flush decoded instns if behaviour of FP instns is to change */
4106 if (v9p->fpu_on != prev_state) {
4107 sp->xicache_instn_flush_pending = true;
4108 set_sync_pending(sp);
4109 }
4110#endif /* FP_DECODE_DISABLED */
4111
4112 v9p->pstate.addr_mask = false;
4113 V9_PSTATE_AM_CHANGED(v9p);
4114
4115
4116
4117 /* OK, based on the trap type, and a few other
4118 * pieces of info ... like what state we're in
4119 * - which state are we headed to ...
4120 * .. RED_tt is set if we saturated TL
4121 */
4122
4123 switch( v9p->state ) {
4124 default:
4125 break;
4126 case V9_User:
4127 switch ( ss_trap_list[actual_tt].from_user) {
4128 case TFlag_Not_Poss:
4129 fatal("Hardware should not be able to generate TT=0x%x from user mode", actual_tt);
4130 case TFlag_Priv:
4131 if (tl<=Q_MAXPTL) goto priv_trap_setup;
4132 goto hyperpriv_trap_setup;
4133 case TFlag_HypPriv:
4134 goto hyperpriv_trap_setup;
4135 default: abort();
4136 }
4137 case V9_Priv:
4138 switch ( ss_trap_list[actual_tt].from_priv) {
4139 case TFlag_Not_Poss:
4140 fatal("Hardware should not be able to generate TT=0x%x from privileged mode", actual_tt);
4141 case TFlag_Priv:
4142 if (tl<=Q_MAXPTL) goto priv_trap_setup;
4143 goto hyperpriv_trap_setup;
4144 case TFlag_HypPriv:
4145 goto hyperpriv_trap_setup;
4146 default: abort();
4147 }
4148 case V9_HyperPriv:
4149 switch ( ss_trap_list[actual_tt].from_hyperpriv) {
4150 case TFlag_Not_Poss:
4151 fatal("Hardware should not be able to generate TT=0x%x from hyper-privileged mode", actual_tt);
4152 case TFlag_Priv:
4153 fatal("Hardware cant generate a trap 0x%x to priv mode from hyper-priv mode", actual_tt);
4154 case TFlag_HypPriv:
4155 if (RED_tt != 0) goto REDstate_trap_setup;
4156 goto hyperpriv_trap_setup;
4157 default: abort();
4158 }
4159 case V9_RED:
4160 if (RED_tt == 0)
4161 RED_tt = SS_trap_RED_state_exception;
4162 if (v9p->had_RED_trap) {
4163 fatal("Caught trap type 0x%x (%s) at pc=0x%llx while "
4164 "in RED state - aborting simulation",
4165 actual_tt, ss_trap_list[actual_tt].trap_namep,
4166 sp->pc);
4167 }
4168 v9p->had_RED_trap = true;
4169 goto REDstate_trap_setup;
4170 }
4171 abort(); /* internal error if we get here ! */
4172
4173
4174
4175 /*
4176 * OK setup for trap into privileged mode
4177 */
4178priv_trap_setup:;
4179
4180 new_trap_pc = v9p->tba | (oldtl != 0 ? (1<<14) : 0) | (tt << 5);
4181
4182 v9p->pstate.priv = true;
4183 v9p->pstate.int_enabled = false; /* pstate.ie = 0 */
4184 prev_state = v9p->pstate.cle;
4185 v9p->pstate.cle = v9p->pstate.tle;
4186 if (v9p->pstate.cle != prev_state)
4187 sp->xdcache_trans_flush_pending = true;
4188
4189 /* hpstate unchanged */
4190
4191 /* adjust and saturate GL appropriately */
4192 ASSERT( v9p->gl <= Q_MAXPGL ); /* internal error if otherwise */
4193 if (v9p->gl < Q_MAXPGL) {
4194 v9p->gl++;
4195 } else {
4196 EXEC_WARNING(("Taking privileged trap with gl value too large (%u) ; saturating to %u (tl=%u tpc=0x%llx, tt=0x%x, actual_tt=0x%x)", v9p->gl, Q_MAXPGL, v9p->tl, N_TPC(v9p, tl), tt, actual_tt));
4197 }
4198 sparcv9_active_globals(sp, v9p->gl);
4199
4200 new_state = V9_Priv;
4201 goto take_trap;
4202
4203 /*
4204 * OK setup for trap into hyper-privileged mode
4205 */
4206hyperpriv_trap_setup:;
4207
4208 new_trap_pc = v9p->htba | (tt << 5);
4209
4210 /* v9p->pstate.priv unchanged */
4211 /* v9p->pstate.mm unchanged */
4212 v9p->pstate.int_enabled = false; /* pstate.ie = 0 */
4213 prev_state = v9p->pstate.cle;
4214 v9p->pstate.cle = false; /* always big endian */
4215 if (v9p->pstate.cle != prev_state)
4216 sp->xdcache_trans_flush_pending = true;
4217
4218 v9p->hpstate.red = false;
4219#ifndef NIAGARA2
4220 v9p->hpstate.tlz = false;
4221#endif
4222 v9p->hpstate.hpriv = true;
4223#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
4224 v9p->hpstate.ibe = false; /* not supported ? FIXME */
4225#endif /* } */
4226
4227 ASSERT( v9p->gl <= (v9p->nglobals-1) );
4228 if (v9p->gl < (v9p->nglobals-1)) {
4229 v9p->gl ++;
4230 } else {
4231 EXEC_WARNING(("Taking hyper-priv trap with gl value too large (%u) ; saturating to %u", v9p->gl, v9p->nglobals-1));
4232 }
4233 sparcv9_active_globals(sp, v9p->gl);
4234
4235 new_state = V9_HyperPriv;
4236 goto take_trap;
4237
4238
4239REDstate_trap_setup:;
4240 EXEC_WARNING(("Entering RED at pc=0x%llx", sp->pc));
4241
4242 new_trap_pc = npp->rstv_addr | (RED_tt << 5);
4243
4244 /* v9p->pstate.priv unchanged */
4245 v9p->pstate.int_enabled = false; /* pstate.ie = 0 */
4246 prev_state = v9p->pstate.cle;
4247 v9p->pstate.cle = false; /* always big endian */
4248 if (v9p->pstate.cle != prev_state)
4249 sp->xdcache_trans_flush_pending = true;
4250 v9p->pstate.mm = v9_mm_tso; /* as per UltraSPARC 2006 sec 12.6.2 */
4251
4252 v9p->hpstate.red = true;
4253 v9p->hpstate.tlz = false;
4254 v9p->hpstate.hpriv = true;
4255#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
4256 v9p->hpstate.ibe = false; /* not supported ? FIXME */
4257#endif /* } */
4258
4259 ASSERT( v9p->gl <= (v9p->nglobals-1) );
4260 if (v9p->gl < (v9p->nglobals-1)) {
4261 v9p->gl ++;
4262 } else {
4263 EXEC_WARNING(("entering RED state with gl value too large (%u) ; saturating to %u", v9p->gl, v9p->nglobals-1));
4264 }
4265 sparcv9_active_globals(sp, v9p->gl);
4266
4267 new_state = V9_RED;
4268 goto take_trap;
4269
4270
4271
4272take_trap:;
4273DBGTSTACK(lprintf(sp->gid, "Trap new pc=0x%llx\n", new_trap_pc););
4274 /* V9_PSTATE_CHANGED(v9p); V9_HPSTATE_CHANGED(sp, v9p); */
4275 if (v9p->state != new_state) {
4276 V9_STATE_CHANGE(sp, v9p, new_state);
4277 /* V9_STATE_CHANGE includes xcache_set_tagstate() */
4278 } else {
4279 xcache_set_tagstate(sp);
4280 }
4281
4282 if (actual_tt == SS_trap_legion_save_state) {
4283 new_trap_pc = options.save_restore.trap_pc;
4284 log_printf(sp->gid,
4285 "ss_take_exception : SS_trap_legion_save_state : divert to %%pc 0x%llx\n",
4286 new_trap_pc);
4287 }
4288 sp->pc = new_trap_pc;
4289 sp->npc = new_trap_pc+4;
4290
4291#if ERROR_TRAP_GEN /* { */
4292 ss_error_taking_trap(sp, (sparcv9_trap_type_t)tt);
4293#endif /* } ERROR_TRAP_GEN */
4294
4295 ss_check_interrupts(sp); /* because of state change */
4296}
4297
4298
4299
4300
4301 /*
4302 * These reset traps always go to the hypervisor
4303 * and always use the reset trap vector
4304 */
4305
4306
4307void ss_reset_trap(simcpu_t * sp, ss_trap_type_t tt)
4308{
4309 sparcv9_cpu_t * v9p;
4310 ss_strand_t * nsp;
4311 ss_proc_t * npp;
4312 uint_t tl;
4313 bool_t prev_state;
4314
4315 v9p = (sparcv9_cpu_t *)(sp->specificp);
4316 nsp = v9p->impl_specificp;
4317
4318 npp = (ss_proc_t *)(sp->config_procp->procp);
4319
4320 switch (tt) {
4321 case SS_trap_power_on_reset:
4322 v9p->tl = v9p->maxtl;
4323 v9p->tt[v9p->tl] = SS_trap_power_on_reset;
4324
4325 v9p->gl = v9p->nglobals - 1;
4326
4327 v9p->pstate.mm = v9_mm_tso; /* TSO */
4328 v9p->pstate.fpu_enabled = v9p->has_fpu;
4329 v9p->pstate.addr_mask = false;
4330 V9_PSTATE_AM_CHANGED(v9p);
4331
4332 v9p->pstate.priv= true;
4333 v9p->pstate.int_enabled = false;
4334 v9p->pstate.cle = false;
4335 v9p->pstate.tle = false;
4336
4337 v9p->hpstate.red= true;
4338 v9p->hpstate.tlz= false;
4339 v9p->hpstate.hpriv= true;
4340#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
4341 v9p->hpstate.ibe= false;
4342#endif /* } */
4343
4344 v9p->softint = 0;
4345
4346 V9_STATE_CHANGE(sp, v9p, V9_RED);
4347
4348 /* stuff for tick interrupts */
4349 v9p->_tick.non_priv_trap = true; /* tick.npt = 1; */
4350 v9p->tick->offset = 0LL;
4351
4352 v9p->_stick.non_priv_trap = true; /* stick.npt = 1; */
4353 v9p->stick->offset = 0LL;
4354
4355
4356#define SS_TICK_CMPR_RESET (1ULL << 63)
4357 ss_tick_cmpr_write(sp, &v9p->tick_cmpr, SS_TICK_CMPR_RESET);
4358 ss_tick_cmpr_write(sp, &v9p->stick_cmpr, SS_TICK_CMPR_RESET);
4359 ss_tick_cmpr_write(sp, &v9p->hstick_cmpr, SS_TICK_CMPR_RESET);
4360 ss_recomp_cycle_target(sp);
4361
4362 break;
4363
4364 case SS_trap_externally_initiated_reset:
4365 tl = v9p->tl+1;
4366 if (tl>v9p->maxtl) tl = v9p->maxtl;
4367 v9p->tl = tl;
4368
4369 N_TPC( v9p, tl ) = sp->pc;
4370 N_TNPC( v9p, tl ) = sp->npc;
4371
4372 N_TT( v9p, tl ) = tt;
4373
4374 /* assemble tstate */
4375 N_TSTATE( v9p, tl ) =
4376 ((v9p->gl & V9_TSTATE_GL_MASK)<<V9_TSTATE_GL_SHIFT) |
4377 ((sp->v9_ccr & V9_TSTATE_CCR_MASK)<<V9_TSTATE_CCR_SHIFT) |
4378 ((sp->v9_asi & V9_TSTATE_ASI_MASK)<<V9_TSTATE_ASI_SHIFT) |
4379 (ss_read_pstate(v9p)<<V9_TSTATE_PSTATE_SHIFT) |
4380 ((v9p->cwp & V9_TSTATE_CWP_MASK)<<V9_TSTATE_CWP_SHIFT);
4381
4382 N_HTSTATE( v9p, tl ) = ss_read_hpstate(v9p);
4383
4384 /* Entering RED state gl can saturate at nglobals-1 */
4385 if (v9p->gl < (v9p->nglobals-1)) v9p->gl ++;
4386 /* sparcv9_active_globals selected at function exit */
4387
4388 v9p->pstate.mm = v9_mm_tso; /* TSO */
4389 v9p->pstate.fpu_enabled = v9p->has_fpu;
4390 v9p->pstate.addr_mask = false;
4391 V9_PSTATE_AM_CHANGED(v9p);
4392
4393 v9p->pstate.priv= true;
4394 v9p->pstate.int_enabled = false;
4395 prev_state = v9p->pstate.cle;
4396 v9p->pstate.cle = v9p->pstate.tle;
4397 if (v9p->pstate.cle != prev_state)
4398 sp->xdcache_trans_flush_pending = true;
4399
4400 v9p->hpstate.red= true;
4401 v9p->hpstate.tlz= false;
4402 v9p->hpstate.hpriv= true;
4403#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
4404 v9p->hpstate.ibe= false;
4405#endif /* } */
4406
4407 /* v9p->softint = 0; FIXME: this what happens on Niagara ? */
4408
4409 V9_STATE_CHANGE(sp, v9p, V9_RED);
4410
4411 break;
4412
4413
4414#if 0 /* { */
4415-- case T_WATCHDOG_RESET:
4416-- if (++sp->trap_level > sp->max_trap_level) {
4417-- sp->trap_level = sp->max_trap_level;
4418-- }
4419-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
4420--
4421-- save_trap_state(sp, sp->trap_level, trap_pc, trap_npc);
4422--
4423-- /*
4424-- * After saving state increment CWP .This is implementation
4425-- * specific to spitfire. Bug:1194954
4426-- */
4427--
4428-- if(from_error_mode){
4429-- /*
4430-- * Modify cwp for window traps.
4431-- * on entering error mode.
4432-- */
4433-- if (error_tt == T_CLEAN_WINDOW) {
4434-- P_CWP = INC_MOD_NWIN(P_CWP);
4435-- if (P_CWP != sp->current_window)
4436-- update_cur_win_regs(sp);
4437-- } else if (is_spill_trap(error_tt)) {
4438-- /* Increment CWP by 2 + CANSAVE. */
4439-- int count = 2 + sp->cansave;
4440-- while (count--) {
4441-- P_CWP = INC_MOD_NWIN(P_CWP);
4442-- }
4443-- if (P_CWP != sp->current_window)
4444-- update_cur_win_regs(sp);
4445-- } else if (is_fill_trap(error_tt)) {
4446-- /* Decrement CWP. */
4447-- P_CWP= DEC_MOD_NWIN(P_CWP);
4448-- /* Update cur_win_regs[]. */
4449-- if (P_CWP != sp->current_window)
4450-- update_cur_win_regs(sp);
4451-- }
4452-- }
4453-- sp->trap_type[sp->trap_level] = from_error_mode ? error_tt: trno;
4454--
4455-- sp->pstate.s.mm = 0x0; /* TSO */
4456-- Old_val = sp->pstate.s.red;
4457-- sp->pstate.s.red = 1;
4458-- PSTATE_RED_CHANGED(sp->pstate.s.red);
4459-- sp->pstate.s.pef = 1;
4460-- sp->pstate.s.am = 0;
4461-- PSTATE_AM_CHANGED(sp->pstate.s.am);
4462-- sp->pstate.s.priv = 1;
4463-- sp->pstate.s.ie = 0;
4464-- sp->pstate.s.ag = 1;
4465-- sp->pstate.s.vg = 0;
4466-- sp->pstate.s.mg = 0;
4467-- sp->pstate.s.cle = sp->pstate.s.tle;
4468--
4469-- set_pc_for_red_mode_trap(sp, T_WATCHDOG_RESET);
4470-- break;
4471--
4472--
4473-- case T_SOFTWARE_RESET:
4474-- if (++sp->trap_level > sp->max_trap_level) {
4475-- sp->trap_level = sp->max_trap_level;
4476-- }
4477-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
4478--
4479-- save_trap_state(sp, sp->trap_level, trap_pc, trap_npc);
4480--
4481-- sp->trap_type[sp->trap_level] = T_SOFTWARE_RESET;
4482--
4483-- sp->pstate.s.mm = 0x0; /* TSO */
4484-- Old_val = sp->pstate.s.red;
4485-- sp->pstate.s.red = 1;
4486-- PSTATE_RED_CHANGED(sp->pstate.s.red);
4487-- sp->pstate.s.pef = 1;
4488-- sp->pstate.s.am = 0;
4489-- PSTATE_AM_CHANGED(sp->pstate.s.am);
4490-- sp->pstate.s.priv = 1;
4491-- sp->pstate.s.ie = 0;
4492-- sp->pstate.s.ag = 1;
4493-- sp->pstate.s.vg = 0;
4494-- sp->pstate.s.mg = 0;
4495-- sp->pstate.s.cle = sp->pstate.s.tle;
4496--
4497-- set_pc_for_red_mode_trap(sp, T_SOFTWARE_RESET);
4498-- break;
4499#endif /* } */
4500
4501 default:
4502 fatal("cpu: unknown reset trap 0x%x.\n", tt);
4503 break;
4504 }
4505
4506 /* setup the mmu_bypass to reflect hpstate */
4507 /* V9_PSTATE_CHANGED(v9p); V9_HPSTATE_CHANGED(sp, v9p); */
4508
4509 sp->pc = npp->rstv_addr | (tt<<5);
4510 sp->npc = sp->pc + 4;
4511
4512 sparcv9_active_window(sp, v9p->cwp);
4513 sparcv9_active_globals(sp, v9p->gl);
4514
4515 v9p->fpu_on = (v9p->pstate.fpu_enabled && v9p->fprs.fef && v9p->has_fpu);
4516#ifdef FP_DECODE_DISABLED
4517 sp->xicache_instn_flush_pending = true; /* for such things as fpu_on changed */
4518 set_sync_pending(sp);
4519#endif /* FP_DECODE_DISABLED */
4520 xcache_set_tagstate(sp);
4521
4522 ss_check_interrupts(sp); /* because of state change */
4523}
4524
4525static void ss_post_precise_trap(simcpu_t * sp, sparcv9_trap_type_t code)
4526{
4527 sparcv9_cpu_t * v9p;
4528 ss_strand_t * nsp;
4529 ss_trap_type_t tt; /* the trap we deliver */
4530 ss_trap_type_t pendtt; /* the trap we deliver */
4531
4532 v9p = (sparcv9_cpu_t *)(sp->specificp);
4533 nsp = v9p->impl_specificp;
4534
4535#ifdef ROCK
4536 if (TM_ACTIVE(nsp)) {
4537 switch((uint_t)code) {
4538 /* Set of all disruptive traps specified in PRM (for rock) */
4539 case SS_trap_sw_recoverable_error:
4540 case SS_trap_interrupt_level_1:
4541 case SS_trap_interrupt_level_2:
4542 case SS_trap_interrupt_level_3:
4543 case SS_trap_interrupt_level_4:
4544 case SS_trap_interrupt_level_5:
4545 case SS_trap_interrupt_level_6:
4546 case SS_trap_interrupt_level_7:
4547 case SS_trap_interrupt_level_8:
4548 case SS_trap_interrupt_level_9:
4549 case SS_trap_interrupt_level_a:
4550 case SS_trap_interrupt_level_b:
4551 case SS_trap_interrupt_level_c:
4552 case SS_trap_interrupt_level_d:
4553 case SS_trap_interrupt_level_e:
4554 case SS_trap_interrupt_level_f:
4555 case SS_trap_hstick_match:
4556 case SS_trap_trap_level_zero:
4557 case SS_trap_hw_corrected_error:
4558 case RK_trap_store_data_value:
4559 case RK_trap_no_retire:
4560 case RK_trap_SIU_inbound_exception:
4561 case RK_trap_data_access_SIU_error:
4562 case RK_trap_hyperprivileged_queue_0:
4563 case RK_trap_hyperprivileged_queue_1:
4564 case SS_trap_cpu_mondo_trap:
4565 case SS_trap_dev_mondo_trap:
4566 case SS_trap_resumable_error:
4567 nsp->tm_fail(sp, V9_CPS_ASYNC);
4568 break; /* Handle the trap since these are disruptive type */
4569 default:
4570 nsp->tm_fail(sp, V9_CPS_PRECISE);
4571 return; /* Return without handling the trap */
4572
4573 }
4574 }
4575#endif
4576
4577 tt = (ss_trap_type_t)code;
4578
4579 /*
4580 * post this trap if it has higher priority than the
4581 * trap already in place
4582 */
4583
4584 pendtt = nsp->pending_precise_tt;
4585 ASSERT( ss_trap_list[tt].trap_namep != (char*)0 ); /* legit HW trap ? */
4586
4587 /* NB larger priority number = lower priority */
4588 if (pendtt==SS_trap_NONE ||
4589 ss_trap_list[pendtt].priority > ss_trap_list[tt].priority) {
4590
4591 nsp->pending_precise_tt = tt;
4592 sp->exception_pending = true;
4593 }
4594}
4595
4596
4597#if 0 /* { */
4598--
4599-- /* Called to execute all SunSPARC synchronous and asynchronous traps. */
4600-- void ss_execute_trap(FcpuT* sp, Word trno, const char* trap_str,
4601-- LWord trap_pc, LWord trap_npc, enum Trap_globals p_globals, bool_t sync_trap)
4602-- {
4603-- Word error_tt;
4604-- Bool from_error_mode = FALSE;
4605-- u_tba_addr tba_addr;
4606-- Byte Old_val;
4607--
4608-- if (trno > MAX_TRAP_NUM) {
4609-- fatal("cpu: called with illegal trap number of 0x%x.\n", trno);
4610-- }
4611--
4612--
4613-- sp->trap_linkage_pending = TRUE;
4614--
4615-- if (sp->trap_level == sp->max_trap_level) {
4616--
4617-- /* ERROR mode. */
4618-- /* If stop_on_reset flag is set, stop the simulation. */
4619-- if (sp->stop_on_reset) {
4620-- /*
4621-- * Modify cwp for window traps.
4622-- * on entering error mode.
4623-- */
4624-- if (trno == T_CLEAN_WINDOW) {
4625-- /* Increment CWP. */
4626-- P_CWP = INC_MOD_NWIN(P_CWP);
4627-- if (P_CWP != sp->current_window)
4628-- update_cur_win_regs(sp);
4629--
4630-- } else if (is_spill_trap(trno)) {
4631-- /* Increment CWP by 2 + CANSAVE. */
4632-- int count = 2 + sp->cansave;
4633-- while (count--) {
4634-- P_CWP = INC_MOD_NWIN(P_CWP);
4635-- }
4636-- if (P_CWP != sp->current_window)
4637-- update_cur_win_regs(sp);
4638--
4639-- } else if (is_fill_trap(trno)) {
4640-- /* Decrement CWP. */
4641-- P_CWP= DEC_MOD_NWIN(P_CWP);
4642-- /* Update cur_win_regs[]. */
4643-- if (P_CWP != sp->current_window)
4644-- update_cur_win_regs(sp);
4645-- }
4646--
4647-- printf("cpu : error mode caused by trap 0x%x (%s)\n", trno, trap_str);
4648-- printf("\tAt time of trap: pc 0x%llx, npc 0x%llx\n",
4649-- (uint64_t)trap_pc, (uint64_t)trap_npc);
4650-- stop_simulation(sp->cmd_ptr);
4651-- return;
4652-- }
4653--
4654-- /*
4655-- * Make the processor look like it halted and then was
4656-- * brought back to life by a watchdog reset.
4657-- */
4658-- error_tt = trno; /* save trno for below */
4659-- from_error_mode = TRUE;
4660--
4661-- /* make processor think it received
4662-- * a watchdog reset
4663-- */
4664-- trno = T_WATCHDOG_RESET;
4665-- }
4666--
4667-- if (is_reset_trap(trno)) {
4668-- execute_reset_trap(sp, trno, from_error_mode, error_tt, trap_pc, trap_npc);
4669-- return;
4670-- }
4671--
4672-- if (sp->trap_level == (sp->max_trap_level - 1) || sp->pstate.s.red) {
4673-- execute_red_mode_trap(sp, trno, trap_pc, trap_npc, p_globals);
4674-- return;
4675-- }
4676--
4677-- /*
4678-- * "Normal" trap processing.
4679-- */
4680--
4681-- tba_addr.l = sp->tba.l;
4682-- tba_addr.s.in_trap = (sp->trap_level > 0);
4683-- sp->trap_level++;
4684--
4685-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
4686--
4687-- save_trap_state(sp, sp->trap_level, trap_pc, trap_npc);
4688--
4689-- /* Modify cwp for window traps. */
4690-- if (trno == T_CLEAN_WINDOW) {
4691--
4692-- /* Increment CWP. */
4693-- P_CWP = INC_MOD_NWIN(P_CWP);
4694-- if (P_CWP != sp->current_window)
4695-- update_cur_win_regs(sp); /* Update cur_win_regs[]. */
4696--
4697-- } else if (is_spill_trap(trno)) {
4698--
4699-- /* Increment CWP by 2 + CANSAVE. */
4700--
4701-- uint32_t cwp = P_CWP;
4702--
4703-- if (sp->cansave == 0) {
4704-- cwp = INC_MOD_NWIN(cwp);
4705-- P_CWP = INC_MOD_NWIN(cwp);
4706-- }
4707-- else {
4708-- int count = 2 + sp->cansave;
4709-- while (count--) {
4710-- P_CWP = INC_MOD_NWIN(P_CWP);
4711-- }
4712-- }
4713--
4714--
4715-- if (P_CWP != sp->current_window) {
4716-- update_cur_win_regs(sp); /* Update cur_win_regs[]. */
4717-- }
4718--
4719-- } else if (is_fill_trap(trno)) {
4720-- /* Decrement CWP. */
4721-- P_CWP= DEC_MOD_NWIN(P_CWP);
4722--
4723-- if (P_CWP != sp->current_window) {
4724-- update_cur_win_regs(sp); /* Update cur_win_regs[]. */
4725-- }
4726-- }
4727--
4728-- Old_val = sp->pstate.s.red;
4729-- sp->pstate.s.red = 0;
4730-- PSTATE_RED_CHANGED(sp->pstate.s.red);
4731-- sp->pstate.s.pef = 1;
4732-- sp->pstate.s.am = 0;
4733-- PSTATE_AM_CHANGED(sp->pstate.s.am);
4734-- sp->pstate.s.priv = 1;
4735-- sp->pstate.s.ie = 0;
4736-- sp->pstate.s.cle = sp->pstate.s.tle;
4737--
4738-- /* Activate the appropriate globals. */
4739-- switch (p_globals) {
4740-- case use_alternate_globals:
4741-- sp->pstate.s.ag = 1;
4742-- sp->pstate.s.vg = 0;
4743-- sp->pstate.s.mg = 0;
4744--
4745-- update_global_regs_il (sp, use_alternate_globals + 1);
4746--
4747-- break;
4748-- case use_mmu_globals:
4749-- sp->pstate.s.ag = 0;
4750-- sp->pstate.s.vg = 0;
4751-- sp->pstate.s.mg = 1;
4752--
4753-- update_global_regs_il (sp, use_mmu_globals + 1);
4754--
4755-- break;
4756-- case use_vector_globals:
4757-- sp->pstate.s.ag = 0;
4758-- sp->pstate.s.vg = 1;
4759-- sp->pstate.s.mg = 0;
4760--
4761-- update_global_regs_il (sp, use_vector_globals + 1);
4762--
4763-- break;
4764-- }
4765--
4766-- /* SL - 05/09/2001 */
4767-- /* repalced the call below by inline function to shorten trap handling */
4768--
4769--
4770-- /* update_global_regs(sp, sp->pstate); */
4771--
4772--
4773-- update_async_trap_pending(sp);
4774--
4775-- #ifdef ECC
4776-- update_error_trap_pending(sp);
4777-- #endif
4778--
4779-- FASTMEM_TL_PSTATE_CHANGE(sp);
4780--
4781-- sp->trap_type[sp->trap_level] = trno;
4782--
4783-- tba_addr.s.tt = sp->trap_type[sp->trap_level];
4784--
4785-- sp->pc = tba_addr.l;
4786-- sp->npc = tba_addr.l + 4;
4787-- sp->cti_executed = TRUE;
4788-- sp->cti_indx = TCC_T;
4789--
4790-- #if 0
4791-- {
4792-- Word tctxt;
4793-- (sp->dmmu->context_select)(sp->dmmu, DEFAULT_DATA_ASI, &tctxt);
4794-- sp->fm.current_ctxt = tctxt;
4795-- TRACEMOD_TTEXT( ("CONTEXT %d",(int)tctxt) );
4796-- }
4797-- #endif
4798--
4799-- }
4800#endif /* } */
4801
4802#if 0 /* { */
4803--
4804-- /**************************************************************/
4805--
4806--
4807-- void
4808-- execute_reset_trap(FcpuT* sp, Word trno, Bool from_error_mode,
4809-- Word error_tt, LWord trap_pc, LWord trap_npc)
4810-- {
4811-- Byte Old_val;
4812--
4813-- switch (trno) {
4814--
4815-- case SS_trap_power_on_reset:
4816-- sp->trap_level = sp->max_trap_level;
4817-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
4818-- sp->trap_type[sp->trap_level] = T_POWER_ON_RESET;
4819--
4820-- sp->pstate.s.mm = 0x0; /* TSO */
4821-- Old_val = sp->pstate.s.red;
4822-- sp->pstate.s.red = 1;
4823-- PSTATE_RED_CHANGED(sp->pstate.s.red);
4824-- sp->pstate.s.pef = 1;
4825-- sp->pstate.s.am = 0;
4826-- PSTATE_AM_CHANGED(sp->pstate.s.am);
4827-- sp->pstate.s.priv = 1;
4828-- sp->pstate.s.ie = 0;
4829-- sp->pstate.s.ag = 1;
4830-- sp->pstate.s.vg = 0;
4831-- sp->pstate.s.mg = 0;
4832-- sp->pstate.s.cle = sp->pstate.s.tle;
4833--
4834-- set_pc_for_red_mode_trap(sp, T_POWER_ON_RESET);
4835--
4836-- /* stuff for tick interrupts */
4837-- sp->tick.nonpriv_trap = 1; /* tick.npt = 1; */
4838-- sp->stick.nonpriv_trap = 1; /* stick.npt = 1; */
4839-- sp->tick.interrupt_enabled = 0; /* tick_cmpr.int_dis = 1; */
4840-- sp->stick.interrupt_enabled = 0; /* stick_cmpr.int_dis = 1; */
4841--
4842-- /* tick & stick scales created when cpu created ? */
4843-- assert(sp->tick.scale != 0.0);
4844--
4845-- ss_recompute_count_target(sp); /* changed tick & stick */
4846--
4847-- break;
4848--
4849-- case T_WATCHDOG_RESET:
4850-- if (++sp->trap_level > sp->max_trap_level) {
4851-- sp->trap_level = sp->max_trap_level;
4852-- }
4853-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
4854--
4855-- save_trap_state(sp, sp->trap_level, trap_pc, trap_npc);
4856--
4857-- /*
4858-- * After saving state increment CWP .This is implementation
4859-- * specific to spitfire. Bug:1194954
4860-- */
4861--
4862-- if(from_error_mode){
4863-- /*
4864-- * Modify cwp for window traps.
4865-- * on entering error mode.
4866-- */
4867-- if (error_tt == T_CLEAN_WINDOW) {
4868-- P_CWP = INC_MOD_NWIN(P_CWP);
4869-- if (P_CWP != sp->current_window)
4870-- update_cur_win_regs(sp);
4871-- } else if (is_spill_trap(error_tt)) {
4872-- /* Increment CWP by 2 + CANSAVE. */
4873-- int count = 2 + sp->cansave;
4874-- while (count--) {
4875-- P_CWP = INC_MOD_NWIN(P_CWP);
4876-- }
4877-- if (P_CWP != sp->current_window)
4878-- update_cur_win_regs(sp);
4879-- } else if (is_fill_trap(error_tt)) {
4880-- /* Decrement CWP. */
4881-- P_CWP= DEC_MOD_NWIN(P_CWP);
4882-- /* Update cur_win_regs[]. */
4883-- if (P_CWP != sp->current_window)
4884-- update_cur_win_regs(sp);
4885-- }
4886-- }
4887-- sp->trap_type[sp->trap_level] = from_error_mode ? error_tt: trno;
4888--
4889-- sp->pstate.s.mm = 0x0; /* TSO */
4890-- Old_val = sp->pstate.s.red;
4891-- sp->pstate.s.red = 1;
4892-- PSTATE_RED_CHANGED(sp->pstate.s.red);
4893-- sp->pstate.s.pef = 1;
4894-- sp->pstate.s.am = 0;
4895-- PSTATE_AM_CHANGED(sp->pstate.s.am);
4896-- sp->pstate.s.priv = 1;
4897-- sp->pstate.s.ie = 0;
4898-- sp->pstate.s.ag = 1;
4899-- sp->pstate.s.vg = 0;
4900-- sp->pstate.s.mg = 0;
4901-- sp->pstate.s.cle = sp->pstate.s.tle;
4902--
4903-- set_pc_for_red_mode_trap(sp, T_WATCHDOG_RESET);
4904-- break;
4905--
4906-- case T_EXTERNAL_RESET:
4907-- if (++sp->trap_level > sp->max_trap_level) {
4908-- sp->trap_level = sp->max_trap_level;
4909-- }
4910-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
4911--
4912-- save_trap_state(sp, sp->trap_level, trap_pc, trap_npc);
4913--
4914-- sp->trap_type[sp->trap_level] = from_error_mode ? error_tt: trno;
4915--
4916-- sp->pstate.s.mm = 0x0; /* TSO */
4917-- Old_val = sp->pstate.s.red;
4918-- sp->pstate.s.red = 1;
4919-- PSTATE_RED_CHANGED(sp->pstate.s.red);
4920-- sp->pstate.s.pef = 1;
4921-- sp->pstate.s.am = 0;
4922-- PSTATE_AM_CHANGED(sp->pstate.s.am);
4923-- sp->pstate.s.priv = 1;
4924-- sp->pstate.s.ie = 0;
4925-- sp->pstate.s.ag = 1;
4926-- sp->pstate.s.vg = 0;
4927-- sp->pstate.s.mg = 0;
4928-- sp->pstate.s.cle = sp->pstate.s.tle;
4929--
4930-- set_pc_for_red_mode_trap(sp, T_EXTERNAL_RESET);
4931-- break;
4932--
4933-- case T_SOFTWARE_RESET:
4934-- if (++sp->trap_level > sp->max_trap_level) {
4935-- sp->trap_level = sp->max_trap_level;
4936-- }
4937-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
4938--
4939-- save_trap_state(sp, sp->trap_level, trap_pc, trap_npc);
4940--
4941-- sp->trap_type[sp->trap_level] = T_SOFTWARE_RESET;
4942--
4943-- sp->pstate.s.mm = 0x0; /* TSO */
4944-- Old_val = sp->pstate.s.red;
4945-- sp->pstate.s.red = 1;
4946-- PSTATE_RED_CHANGED(sp->pstate.s.red);
4947-- sp->pstate.s.pef = 1;
4948-- sp->pstate.s.am = 0;
4949-- PSTATE_AM_CHANGED(sp->pstate.s.am);
4950-- sp->pstate.s.priv = 1;
4951-- sp->pstate.s.ie = 0;
4952-- sp->pstate.s.ag = 1;
4953-- sp->pstate.s.vg = 0;
4954-- sp->pstate.s.mg = 0;
4955-- sp->pstate.s.cle = sp->pstate.s.tle;
4956--
4957-- set_pc_for_red_mode_trap(sp, T_SOFTWARE_RESET);
4958-- break;
4959--
4960-- default:
4961-- fatal("cpu: unknown reset trap 0x%x.\n", trno);
4962-- break;
4963-- }
4964--
4965-- update_global_regs(sp, sp->pstate);
4966-- update_async_trap_pending(sp);
4967--
4968-- #ifdef ECC
4969-- update_error_trap_pending(sp);
4970-- #endif
4971--
4972-- FASTMEM_TL_PSTATE_CHANGE(sp);
4973--
4974-- sp->cti_executed = TRUE;
4975-- sp->cti_indx = TCC_T;
4976--
4977-- /* setup for the fast memory stuff ... -ash */
4978--
4979--
4980-- /* fastmem_flush(&(sp->fm), 0, 0); */ /* flush all pages */
4981--
4982--
4983-- #if 0
4984-- { Word tctxt;
4985-- (sp->dmmu->context_select)(sp->dmmu, DEFAULT_DATA_ASI, &tctxt);
4986-- sp->fm.current_ctxt = tctxt;
4987-- TRACEMOD_TTEXT( ("CONTEXT %d",(int)tctxt) );
4988-- }
4989-- #endif
4990--
4991-- }
4992--
4993-- /*
4994-- * Called when a trap occurs in RED mode or a trap puts the processor
4995-- * into RED mode (when trap_level is max_trap_level less 1).
4996-- */
4997-- void
4998-- execute_red_mode_trap(FcpuT* sp, Word trno, LWord trap_pc,
4999-- LWord trap_npc, enum Trap_globals p_globals)
5000-- {
5001-- Byte Old_val;
5002--
5003-- sp->trap_level ++;
5004-- TRACEMOD_TTEXT( ("TRAP_LEVEL %d",(int)sp->trap_level) );
5005--
5006-- save_trap_state(sp, sp->trap_level, trap_pc, trap_npc);
5007--
5008-- sp->trap_type[sp->trap_level] = trno;
5009--
5010-- /* Modify cwp for window traps. */
5011-- if (trno == T_CLEAN_WINDOW) {
5012-- /* Increment CWP. */
5013-- P_CWP = INC_MOD_NWIN(P_CWP);
5014-- if (P_CWP != sp->current_window)
5015-- update_cur_win_regs(sp); /* Update cur_win_regs[]. */
5016-- } else if (is_spill_trap(trno)) {
5017-- /* Increment CWP by 2 + CANSAVE. */
5018-- int count = 2 + sp->cansave;
5019--
5020-- while (count--) {
5021-- P_CWP = INC_MOD_NWIN(P_CWP);
5022-- }
5023-- if (P_CWP != sp->current_window)
5024-- update_cur_win_regs(sp); /* Update cur_win_regs[]. */
5025-- } else if (is_fill_trap(trno)) {
5026-- /* Decrement CWP. */
5027-- P_CWP= DEC_MOD_NWIN(P_CWP);
5028-- if (P_CWP != sp->current_window)
5029-- update_cur_win_regs(sp); /* Update cur_win_regs[]. */
5030-- }
5031-- sp->pstate.s.mm = 0x0; /* TSO */
5032-- Old_val = sp->pstate.s.red;
5033-- sp->pstate.s.red = 1;
5034-- PSTATE_RED_CHANGED(sp->pstate.s.red);
5035-- sp->pstate.s.pef = 1;
5036-- sp->pstate.s.am = 0;
5037-- PSTATE_AM_CHANGED(sp->pstate.s.am);
5038-- sp->pstate.s.priv = 1;
5039-- sp->pstate.s.ie = 0;
5040-- sp->pstate.s.cle = sp->pstate.s.tle;
5041--
5042-- /* Activate the appropriate globals. */
5043-- switch (p_globals) {
5044-- case use_alternate_globals:
5045-- sp->pstate.s.ag = 1;
5046-- sp->pstate.s.vg = 0;
5047-- sp->pstate.s.mg = 0;
5048-- break;
5049-- case use_mmu_globals:
5050-- sp->pstate.s.ag = 0;
5051-- sp->pstate.s.vg = 0;
5052-- sp->pstate.s.mg = 1;
5053-- break;
5054-- case use_vector_globals:
5055-- sp->pstate.s.ag = 0;
5056-- sp->pstate.s.vg = 1;
5057-- sp->pstate.s.mg = 0;
5058-- break;
5059-- }
5060--
5061-- update_global_regs(sp, sp->pstate);
5062-- update_async_trap_pending(sp);
5063--
5064-- #ifdef ECC
5065-- update_error_trap_pending(sp);
5066-- #endif
5067--
5068-- FASTMEM_TL_PSTATE_CHANGE(sp);
5069--
5070-- set_pc_for_red_mode_trap(sp, T_RED_MODE_EXCEPTION);
5071-- sp->cti_executed = TRUE;
5072-- sp->cti_indx = TCC_T;
5073--
5074-- /* setup for the fast memory stuff ... -ash */
5075--
5076--
5077-- /* fastmem_flush(&(sp->fm), 0, 0); */ /* flush all pages */
5078--
5079-- #if 0
5080-- {
5081-- Word tctxt;
5082-- (sp->dmmu->context_select)(sp->dmmu, DEFAULT_DATA_ASI, &tctxt);
5083-- sp->fm.current_ctxt = tctxt;
5084-- TRACEMOD_TTEXT( ("CONTEXT %d",(int)tctxt) );
5085-- }
5086-- #endif
5087--
5088-- }
5089--
5090--
5091--
5092--
5093--
5094--
5095-- void
5096-- save_trap_state(FcpuT* sp, Byte level, LWord trap_pc, LWord trap_npc)
5097-- {
5098--
5099--
5100-- sp->tstate[level].s.ccr = sp->ccr.b;
5101-- sp->tstate[level].s.asi = sp->asi_reg;
5102-- sp->tstate[level].s.cwp = P_CWP;
5103-- sp->tstate[level].s.pstate = sp->pstate.w;
5104--
5105-- #if 0
5106-- LO_W(trap_pc) &= ~0x3; /* Blow away lower two bits */
5107-- LO_W(trap_npc) &= ~0x3;
5108-- #endif
5109--
5110-- sp->was_tpc_in_hole[level] = FALSE;
5111-- sp->was_tnpc_in_hole[level] = FALSE;
5112-- sp->orig_tnpc[level] = trap_npc;
5113--
5114-- if (sp->annul) {
5115-- sp->tpc[level] = trap_npc;
5116-- sp->tnpc[level] = trap_npc + 4;
5117-- sp->annul = FALSE;
5118-- } else {
5119-- sp->tpc[level] = trap_pc;
5120-- sp->tnpc[level] = trap_npc;
5121-- }
5122--
5123-- }
5124--
5125#endif /* } */
5126
5127
5128
5129
5130
5131
5132
5133 /*************************************************************
5134 *
5135 * ASI access support functions (and instruction impls)
5136 *
5137 *************************************************************/
5138
5139
5140static void ss_xdc_miss(simcpu_t * sp, uint64_t * regp, tvaddr_t addr, maccess_t op)
5141{
5142 sparcv9_cpu_t * v9p;
5143 ss_strand_t * nsp;
5144 mem_flags_t mflags;
5145 uint_t context_type;
5146
5147 v9p = (sparcv9_cpu_t *)(sp->specificp);
5148 nsp = v9p->impl_specificp;
5149
5150 context_type = (v9p->tl>0) ? ss_ctx_nucleus : ss_ctx_primary;
5151
5152 mflags = MF_Normal;
5153
5154 if (V9_User != v9p->state) mflags |= MF_Has_Priv;
5155 if (nsp->mmu_bypass) mflags |= MF_MMU_Bypass;
5156 /* V9_ASI_IMPLICIT takes little endian from CLE */
5157 if (v9p->pstate.cle) mflags |= MF_Little_Endian;
5158
5159 ASSERT(!IS_V9_MA_ATOMIC(op & MA_Op_Mask));
5160
5161 ASSERT(0LL==sp->intreg[Reg_sparcv9_g0]);
5162
5163 ss_memory_asi_access(sp, op, regp, mflags, SS_ASI_PRIMARY, context_type,
5164 (1<<(op & MA_Size_Mask))-1, addr, 0);
5165
5166 ASSERT(0LL==sp->intreg[Reg_sparcv9_g0]);
5167}
5168
5169
5170 /****************************************************************
5171 *
5172 * TLB code
5173 *
5174 ****************************************************************/
5175
5176
5177
5178
5179void ss_tlb_init(ss_tlb_t * tlbp, uint_t nentries)
5180{
5181 int i;
5182
5183 tlbp->freep = (tlb_entry_t *)0;
5184 tlbp->nentries = nentries;
5185 tlbp->tlb_entryp = Xcalloc(nentries, tlb_entry_t);
5186
5187 /* clear each entry and stack on the free list */
5188 for (i=nentries-1; i>=0; i--) {
5189 /* FIXME: give the tlb entry fields some default power on value ? */
5190 ss_free_tlb_entry(tlbp, &(tlbp->tlb_entryp[i]));
5191 }
5192
5193 /* Now init and clear the hash */
5194 for (i=0; i<SS_TLB_HASH_ENTRIES; i++) {
5195 tlb_hash_bucket_t * hbp;
5196
5197 hbp = &(tlbp->hash[i]);
5198
5199 hbp->ptr = NULL;
5200 }
5201
5202 tlbp->shares = 0;
5203
5204#if SS_TLB_REPLACE_RROBIN /* { */
5205 tlbp->last_replaced = 0;
5206#endif /* } */
5207 RW_lock_init(&tlbp->rwlock, NULL);
5208}
5209
5210void ss_tlb_flush_shares(simcpu_t * sp, ss_tlb_t * tlbp, bool_t is_immu)
5211{
5212 simcpu_t * xsp;
5213 sparcv9_cpu_t * v9p;
5214 ss_strand_t * nsp;
5215 int i;
5216 uint_t found = 0;
5217
5218 for (i = 0; i < simcpu_list.count; i++) {
5219 xsp = LIST_ENTRY(simcpu_list, i);
5220 v9p = (sparcv9_cpu_t *)(xsp->specificp);
5221 nsp = v9p->impl_specificp;
5222 if (nsp->itlbp == tlbp || nsp->dtlbp == tlbp) {
5223 found++;
5224 if (xsp != sp) {
5225 if (is_immu)
5226 xsp->xicache_trans_flush_pending = true;
5227 else
5228 xsp->xdcache_trans_flush_pending = true;
5229 }
5230 }
5231 }
5232 ASSERT(found == tlbp->shares);
5233}
5234
5235void ss_tlb_scrub(simcpu_t * sp, ss_tlb_t * tlbp, bool_t is_immu)
5236{
5237 tlb_entry_t * tep;
5238 int i;
5239 bool_t need_flush = false;
5240
5241 RW_wrlock(&tlbp->rwlock);
5242
5243 tep = &(tlbp->tlb_entryp[0]);
5244 for (i=tlbp->nentries-1; i>=0; i--, tep++) {
5245 if (tep->hashidx != -1) {
5246 need_flush = true;
5247 ss_tlb_unhash(tlbp, tep);
5248 ss_free_tlb_entry(tlbp, tep);
5249 }
5250 }
5251
5252#if SS_TLB_REPLACE_RROBIN /* { */
5253 tlbp->last_replaced = 0;
5254#endif /* } */
5255
5256 RW_unlock(&tlbp->rwlock);
5257
5258 if (need_flush) {
5259 if (is_immu)
5260 sp->xicache_trans_flush_pending = true;
5261 else
5262 sp->xdcache_trans_flush_pending = true;
5263 if (tlbp->shares > 1) {
5264 ss_tlb_flush_shares(sp, tlbp, is_immu);
5265 }
5266 }
5267}
5268
5269
5270
5271
5272 /*
5273 * assumes you hold any appropriate locks when calling
5274 */
5275
5276void ss_free_tlb_entry(ss_tlb_t * tlbp, tlb_entry_t * tep)
5277{
5278 /* only write to fields that can't be read by software */
5279 /* and ensure this entry is effectively marked "invalid" */
5280 tep->match_shift = 0;
5281 tep->flags = 0;
5282 tep->match_context = SS_TLB_INVALID_CONTEXT;
5283 tep->hashidx = -1;
5284#if defined(NIAGARA1)
5285 tep->data &= ~(1ull << SUN4U_TTED_V_BIT);
5286#elif defined(ROCK)
5287 tep->data &= ~((1ull << SUN4V_TTED_V_BIT) |
5288 (1ull << ROCK_DATA_ACCESS_V1_BIT));
5289#else
5290 tep->data &= ~(1ull << SUN4V_TTED_V_BIT);
5291#endif
5292
5293 /* assign to free list */
5294 tep->nextp = tlbp->freep;
5295 tlbp->freep = tep;
5296}
5297
5298
5299void ss_tlb_unhash(ss_tlb_t * tlbp, tlb_entry_t * tep)
5300{
5301 tlb_entry_t ** bp, *p;
5302
5303 ASSERT( tep->hashidx != -1 );
5304
5305 /* We'll barf any panic if we can't find the entry on the list */
5306 /* but this cant ever happen right ! :-) */
5307 for (bp = &(tlbp->hash[tep->hashidx].ptr); (p=*bp)!=tep; bp=&(p->nextp));
5308
5309 *bp = p->nextp;
5310
5311 tep->hashidx = -1;
5312}
5313
5314void ss_tlb_unfree(ss_tlb_t * tlbp, tlb_entry_t * tep)
5315{
5316 tlb_entry_t ** bp, *p;
5317
5318 ASSERT( tep->hashidx == -1 );
5319
5320 /* We'll barf any panic if we can't find the entry on the list */
5321 /* but this cant ever happen right ! :-) */
5322 for (bp = &(tlbp->freep); (p=*bp)!=tep; bp=&(p->nextp));
5323
5324 *bp = p->nextp;
5325}
5326
5327
5328
5329/*
5330 * Niagara 1:
5331 * - demap all demaps all entries that DO NOT have their locked bit set
5332 * - demap page & context demaps matching entries even if their locked bits are set.
5333 *
5334 * Niagara 2:
5335 * - removes the lock bit support
5336 * - adds a demap all page operation, which demaps all pages with R=1 from the TLB.
5337 */
5338bool_t ss_demap(simcpu_t * sp, ss_demap_t op, ss_mmu_t * mmup, ss_tlb_t * tlbp, uint_t partid, bool_t is_real, uint_t context, tvaddr_t addr)
5339{
5340 matchcontext_t match_context;
5341 tlb_entry_t * tep;
5342 uint_t i;
5343 bool_t need_flush = false;
5344
5345 match_context = is_real ? SS_TLB_REAL_CONTEXT : context;
5346
5347 switch (op) {
5348 case NA_demap_page:
5349 DBGMMU( lprintf(sp->gid, "demap_page: part=%x ctx=%x va=0x%llx r:%u\n", partid, context, addr, is_real); );
5350 break;
5351 case NA_demap_all:
5352 DBGMMU( lprintf(sp->gid, "demap_all: part=%x r:%u\n", partid, is_real); );
5353 break;
5354#ifdef NIAGARA2
5355 case NA_demap_all_page:
5356 DBGMMU( lprintf(sp->gid, "demap_all_page: r:%u\n", is_real); );
5357 break;
5358#endif
5359#ifdef NIAGARA1
5360 case NA_demap_init:
5361 DBGMMU( lprintf(sp->gid, "demap_init\n"); );
5362 break;
5363#endif
5364 case NA_demap_context:
5365 /*
5366 * remove TLB entries that match the specified context, partid and R=0
5367 * (true for both N1 and N2, see to N1 PRM Rev 1.5 and N2 PM Rev 0.8)
5368 */
5369 DBGMMU( lprintf(sp->gid, "demap_ctx: part=%x ctx=%x r:%u\n", partid, context, is_real); );
5370 if (is_real) return false;
5371 break;
5372#ifdef ROCK
5373 case NA_demap_real:
5374 DBGMMU( lprintf(sp->gid, "demap_real: part=%x r:%u\n", partid, is_real); );
5375 /*
5376 * This operation is supposed to remove all real TLB entries that match
5377 * the partid, so we force match_context to SS_TLB_REAL_CONTEXT and
5378 * treat this like a NA_demap_page and remove any entry which matches
5379 * context and partid.
5380 */
5381 match_context = SS_TLB_REAL_CONTEXT;
5382 break;
5383#endif
5384 default:
5385 return false;
5386 }
5387
5388 RW_wrlock(&tlbp->rwlock);
5389
5390 /*
5391 * First lets look for potentially matching pages we may have to
5392 * de-map first. We demap the old entry if it incorporates our new
5393 * page, or vice-versa.
5394 */
5395
5396 tep = &(tlbp->tlb_entryp[0]);
5397 for (i=tlbp->nentries; i>0; i--, tep++) {
5398
5399 /* ignore this entry if not in use - i.e. not on hash list */
5400 if (tep->hashidx == -1) continue;
5401
5402 switch (op) {
5403#ifdef NIAGARA2
5404 case NA_demap_all_page:
5405 if (tep->is_real != is_real) break;
5406 goto matching_pid;
5407#endif
5408 case NA_demap_all:
5409#ifdef NIAGARA1
5410 if (tep->flags & SS_TLB_FLAG_LOCKED) break;
5411#endif
5412 goto matching_pid;
5413 case NA_demap_page:
5414 if (((tep->tag_pfn ^ addr)>>tep->match_shift)!=0LL) break;
5415 goto matching_ctx;
5416#ifdef ROCK
5417 case NA_demap_real:
5418 /* fall through */
5419#endif
5420 case NA_demap_context:
5421matching_ctx:
5422 if (tep->match_context != match_context) break;
5423matching_pid:
5424 if (tep->partid != partid) break;
5425 /* fall thru */
5426#ifdef NIAGARA1
5427 case NA_demap_init:
5428#endif
5429 /* matching entry - put back on the free list */
5430 need_flush = true;
5431 ss_tlb_unhash(tlbp, tep);
5432 ss_free_tlb_entry( tlbp, tep );
5433
5434#if ERROR_INJECTION
5435 DBGERR( lprintf(sp->gid, "ss_demap(): errorp->itep=%x"
5436 " errorp->dtep=%x tep=%x\n",
5437 sp->errorp->itep, sp->errorp->dtep, tep); );
5438 tlb_entry_error_match(sp, mmup, tep);
5439#endif
5440
5441 break;
5442 default:
5443 fatal("Internal error: illegal demap op (0x%x)", op);
5444 }
5445 }
5446 RW_unlock(&tlbp->rwlock);
5447
5448#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
5449 if (need_flush) {
5450 if (mmup->is_immu)
5451 sp->xicache_trans_flush_pending = true;
5452 else
5453 sp->xdcache_trans_flush_pending = true;
5454 if (tlbp->shares > 1) {
5455 ss_tlb_flush_shares(sp, tlbp, mmup->is_immu);
5456 }
5457 }
5458#endif /* } */
5459
5460 return true;
5461}
5462
5463
5464#ifdef HW_TABLEWALK
5465
5466 /****************************************************************
5467 *
5468 * HW tablewalk code
5469 *
5470 ****************************************************************/
5471
5472/*
5473 * This function implements the hardware tablewalk for Niagara 2 and Rock
5474 * to service the reload request from the TLBs. The sequence of
5475 * matching the TTEs and reloading the new TLB entry is as follows:
5476 *
5477 * - access all configured TSBs to find an TTE that matches the
5478 * vpn (passed in as 'va') and the context of the request
5479 *
5480 * - translate the RPN of the matching TTE into a PPN
5481 *
5482 * - call ss_tlb_insert to load the matching TTE into TLB
5483 *
5484 * - return a specific trap code to indicate the completion status:
5485 *
5486 * a) trap_NONE:
5487 *
5488 * a match is found, and TLB reload is successful
5489 *
5490 * b) {instruction,data}_invalid_TSB_entry/IAE_unauth_access:
5491 *
5492 * a match is found, but an error occurred during
5493 * the RPN-> PPN translation
5494 *
5495 * c) {instruction,data}_access_MMU_miss:
5496 *
5497 * tablewalk is enabled, but a match is not found
5498 * or the TLB reload is not successful
5499 *
5500 * d) fast_{instruction,data}_access_MMU_miss:
5501 *
5502 * tablewalk on all TSBs are disabled
5503 *
5504 */
5505ss_trap_type_t ss_hardware_tablewalk(simcpu_t *sp, ss_mmu_t * mmup, ss_tlb_t *tlbp, tvaddr_t va, uint_t context_type, uint_t *flags, uint64_t *pa_offset)
5506{
5507 sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
5508 ss_strand_t *nsp = v9p->impl_specificp;
5509
5510 ss_trap_type_t miss_trap_type = SS_trap_NONE;
5511 ss_tsb_info_t *tsb_config_regp;
5512 tvaddr_t tsb_base;
5513 bool_t hwtw_enabled = false;
5514 uint_t i, ctrl, context, context0, context1;
5515 tvaddr_t va_22;
5516
5517 /*
5518 * Figure out the context value. Note that the shared context
5519 * value is not really used in HW TW other than for determining
5520 * which context to insert the entry with (based on the
5521 * use_context0/1 bits)
5522 */
5523 switch (context_type) {
5524 case ss_ctx_primary:
5525 context0 = nsp->pri_context;
5526 context1 = nsp->pri_context1;
5527 break;
5528 case ss_ctx_secondary:
5529 context0 = nsp->sec_context;
5530 context1 = nsp->sec_context1;
5531 break;
5532 case ss_ctx_nucleus:
5533 context0 = SS_NUCLEUS_CONTEXT;
5534 context1 = context0;
5535 break;
5536 default:
5537 fatal("ss_hardware_tablewalk: Internal Error. Not expecting "
5538 "context type 0x%x\n", context_type);
5539 }
5540
5541 if (context0 == 0) {
5542 tsb_config_regp = &nsp->mmu_zero_ctxt_tsb_config[0];
5543 } else {
5544 tsb_config_regp = &nsp->mmu_nonzero_ctxt_tsb_config[0];
5545 }
5546
5547 va_22 = va >> 22;
5548
5549 /*
5550 * walk through all four TSBs to find an tte entry that matches
5551 * the va and the context of the request
5552 */
5553 for (i=0; i<4; i++, tsb_config_regp++) {
5554 uint_t tte_context, tte_ps, tte_idx, tte_ep;
5555 uint64_t tte_entry[2];
5556 tvaddr_t tte_va, tte_ra, tte_pa;
5557 uint8_t *tte_addr;
5558
5559 /*
5560 * first check if the tablewalk on this TSB is enabled
5561 * (controled by the enable bit of tsb_config_reg)
5562 */
5563 if (!tsb_config_regp->enable) continue;
5564
5565 hwtw_enabled = true;
5566
5567 /*
5568 * calculate the TSB pointer based on the given VA and
5569 * TSB configuration register.
5570 */
5571 tte_addr = ss_make_tsb_pointer_int(va, tsb_config_regp);
5572
5573 /*
5574 * fetch the tte entry from the memory (each taken two 8 bytes)
5575 */
5576 if (!ss_hwtw_get_tte_entry(sp, tte_addr, &tte_entry[0])) {
5577 /* Shouldn't happen under normal operation */
5578 EXEC_WARNING(("ss_hardware_tablewalk: ss_hwtw_get_tte_entry() failed.\n"));
5579 continue;
5580 }
5581
5582DBGMMU( lprintf(sp->gid, "ss_hardware_tablewalk check tsb%u pa=0x%llx: va>>22=0x%llx ctx=0x%x/0x%x tag=0x%llx data=0x%llx\n", i, tte_addr, va_22, context0, context1, tte_entry[0], tte_entry[1]););
5583
5584 /*
5585 * validate the V bit, continue searching other TSBs if invalid
5586 */
5587 if (!SUN4V_TTED_V(tte_entry[1])) continue;
5588
5589 /*
5590 * sun4v Solaris uses the reserved bits to flag SW bugs,
5591 * ignore this tte entry if any of these reserved bits are set
5592 */
5593 if (SUN4V_TTET_RSVD(tte_entry[0])) continue;
5594
5595 /*
5596 * check the fetched tte for a match
5597 */
5598 tte_context = SUN4V_TTET_CTXT(tte_entry[0]);
5599 tte_va = SUN4V_TTET_VA(tte_entry[0]);
5600 tte_ep = SUN4V_TTED_EP(tte_entry[1]);
5601 tte_ra = SUN4V_TTED_RA(tte_entry[1]);
5602 tte_ps = SUN4V_TTED_PS(tte_entry[1]);
5603
5604 /*
5605 * determine the context to check in terms of bit 62 and 61 of the tsb_config_reg:
5606 * (see 13.11.11 of N2 PRM Rev 1.1 and section 18.5.4 of SPA 2.0 Draft 0.7.1)
5607 *
5608 * - requesting context is zero (nucleus), both use_context_0 and use_context_1 are
5609 * ignored, but hwtw behaves as if these two bits are zero (so there is a context
5610 * comparison, i.e. to check if tte_context == 0)
5611 *
5612 * - context ID-match mode (use_context_0==0 && use_context_1==0):
5613 * context field of TTE is matched against the context of the request
5614 *
5615 * - context ID-ignore mode (use_context_0==1 || use_context_1==1):
5616 * context field of TTE is ignored, load value of Context Register 0 or 1 to TLB
5617 */
5618
5619 if (context0 == SS_NUCLEUS_CONTEXT) {
5620 if (tte_context != SS_NUCLEUS_CONTEXT) continue;
5621 context = SS_NUCLEUS_CONTEXT;
5622 } else {
5623 if (tsb_config_regp->use_context_0) {
5624 context = context0;
5625 } else if (tsb_config_regp->use_context_1) {
5626 context = context1;
5627 } else /* use_context_0 == use_context_1 == 0 */ {
5628 if (tte_context != context0 &&
5629 tte_context != context1)
5630 continue;
5631 context = tte_context;
5632 }
5633 }
5634
5635 /*
5636 * In both Niagara2 and Rock, it is okay to match if the
5637 * page size of the tsb_config_reg does not match the page
5638 * size of the tte.
5639 * More specifically:
5640 * if page size of TTE >= page size of TSB, then match OK
5641 * if page size of TTE < page size of TSB, then no match
5642 *
5643 * The VA mask bits used in a comparison for a match
5644 * are determined by the TSB page size.
5645 *
5646 */
5647 if (((tte_va ^ va_22) >> tsb_config_regp->tag_match_shift)==0 &&
5648 tte_ps>=tsb_config_regp->page_size) {
5649 /*
5650 * a matching tte is found, check its EP bit for ITLB miss
5651 */
5652 if (mmup->is_immu && (!tte_ep)) {
5653 DBGMMU(lprintf(sp->gid,"ss_hardware_tablewalk: false hit on ITLB miss (EP bit unset): va=0x%llx\n", va); );
5654 return (SS_trap_IAE_unauth_access);
5655 }
5656
5657 /*
5658 * the ra_not_pa bit determines if this TSB contains RAs or PAs:
5659 * (if ra_not_pa is set, do RPN -> PPN translation, otherwise
5660 * the RA is treated as PA)
5661 */
5662 if (!tsb_config_regp->ra_not_pa) {
5663 tte_pa = tte_ra;
5664 } else {
5665 /*
5666 * setup trap type for error occurred in RPN->PPN translation
5667 */
5668 if (mmup->is_immu)
5669 miss_trap_type = SS_trap_instruction_invalid_TSB_entry;
5670 else
5671 miss_trap_type = SS_trap_data_invalid_TSB_entry;
5672
5673 /*
5674 * See if we can find a conversion for this RA
5675 */
5676 if (ss_hwtw_convert_ra_to_pa(tte_ra, &tte_pa, nsp, tte_ps)) {
5677 /*
5678 * RA -> PA conversion found.
5679 * Reassemble the matching TTE data entry with the PPN translation
5680 */
5681 tte_entry[1] &= ~SUN4V_PN_MASK;
5682 tte_entry[1] |= tte_pa & SUN4V_PN_MASK;
5683
5684 /*
5685 * set the trap flag to direct the call to tlb_reload
5686 */
5687 miss_trap_type = SS_trap_NONE;
5688 }
5689 }
5690
5691 if (miss_trap_type != SS_trap_NONE) {
5692 DBGMMU(lprintf(sp->gid, "ss_hardware_tablewalk: false hit (invalid tte): va=0x%llx tte_ra=0x%llx\n", va, tte_ra); );
5693 return (miss_trap_type);
5694 }
5695
5696 /*
5697 * update tag access register (we use macros because this is somewhat
5698 * chip-specific).
5699 */
5700 UPDATE_MMU_TAG_ACCESS(mmup, va, context);
5701
5702 DBGMMU( lprintf(sp->gid, "ss_hardware_tablewalk hit: va=0x%llx data=0x%llx ctx=0x%x\n", va, tte_entry[1], context););
5703
5704 /*
5705 * Insert this TTE into the TLB.
5706 */
5707 miss_trap_type = ss_tlb_insert(sp, mmup, tlbp, nsp->partid, false, tte_entry[1], flags, pa_offset);
5708
5709 return (miss_trap_type);
5710 }
5711 }
5712
5713#ifdef ROCK
5714 /*
5715 * Unlike N2, if we are in this routine, it means HWTW was enabled and so
5716 * we will issue a "slow" MMU trap regardless of whether all four TSB
5717 * config registers where valid or not.
5718 */
5719 hwtw_enabled = true;
5720#endif
5721 /*
5722 * if we are here, either a match was not found or the tablewalk is disabled
5723 */
5724 if (mmup->is_immu) {
5725 if (hwtw_enabled)
5726 miss_trap_type = SS_trap_instruction_access_MMU_miss;
5727 else
5728 miss_trap_type = SS_trap_fast_instruction_access_MMU_miss;
5729 } else {
5730 if (hwtw_enabled)
5731 miss_trap_type = SS_trap_data_access_MMU_miss;
5732 else
5733 miss_trap_type = SS_trap_fast_data_access_MMU_miss;
5734 }
5735
5736 return (miss_trap_type);
5737}
5738
5739
5740uint8_t *ss_hwtw_find_base(simcpu_t *sp, ss_tsb_info_t *tsb_config_reg)
5741{
5742 domain_t *domainp;
5743 config_proc_t *config_procp;
5744 config_addr_t *capsrc;
5745 uint8_t *srcbufp;
5746 tpaddr_t extent;
5747
5748 config_procp = sp->config_procp;
5749 domainp = config_procp->domainp;
5750
5751 capsrc = find_domain_address(domainp, tsb_config_reg->tsb_base);
5752 if (capsrc == NULL) {
5753 EXEC_WARNING(("@ pc=0x%llx : ss_hwtw_find_base: src address not valid",sp->pc));
5754 return NULL;
5755 }
5756 /*
5757 * try and get the buffer pointer
5758 */
5759 extent = capsrc->config_devp->dev_typep->dev_cacheable(capsrc, DA_Load,
5760 tsb_config_reg->tsb_base-capsrc->baseaddr, &srcbufp);
5761 if (extent < (1ull << (13+tsb_config_reg->tsb_size))) {
5762 EXEC_WARNING(("@ pc=0x%llx : ss_hwtw_find_base: src not large enough",sp->pc));
5763 return NULL;
5764 }
5765
5766 return srcbufp;
5767}
5768
5769
5770/*
5771 * Get a tte entry from memory via a 128 bit attomic load
5772 */
5773static bool_t ss_hwtw_get_tte_entry(simcpu_t *sp, uint8_t * tte_addr, uint64_t *ttep)
5774{
5775 /*
5776 * do an atomic load of the TTE entry
5777 */
5778 host_atomic_get128be((uint64_t *)tte_addr, ttep, &ttep[1]);
5779#if HOST_CPU_LITTLE_ENDIAN
5780 *ttep = BSWAP_64(*ttep);
5781 *(ttep + 1) = BSWAP_64(*(ttep + 1));
5782#endif
5783
5784 return true;
5785}
5786
5787#endif /* HW_TABLEWALK */
5788
5789/*
5790 * XOR all bits to get a single bit result.
5791 * Used for parity bit generation.
5792 */
5793uint64_t xor_bits(uint64_t n)
5794{
5795 n = (n ^ (n >> 32)) & 0xffffffff;
5796 n = (n ^ (n >> 16)) & 0xffff;
5797 n = (n ^ (n >> 8)) & 0xff;
5798 n = (n ^ (n >> 4)) & 0xf;
5799 n = (n ^ (n >> 2)) & 0x3;
5800 n = (n ^ (n >> 1)) & 0x1;
5801 return n;
5802}
5803
5804 /****************************************************************
5805 *
5806 * L1/L2 cache code
5807 *
5808 ****************************************************************/
5809
5810
5811void ss_l1_cache_init(ss_l1_cache_t * cachep, uint32_t cachesize, bool_t is_icache)
5812{
5813 uint_t tagsize, datasize;
5814 int i;
5815
5816 /*
5817 * Allocate icache/dcache memory for data and tags
5818 * Icache:
5819 * 64bit diag tag per 32byte instn block
5820 * 64bit diag data per 32bits instn data (instn + switch/parity bits)
5821 * Dcache:
5822 * 64bit tag per 16byte data block
5823 * 64bit diag data mirrors cache data
5824 */
5825
5826 tagsize = is_icache ? cachesize/4 : cachesize/2;
5827 datasize = is_icache ? cachesize*2 : cachesize;
5828
5829 cachep->tagp = Xmalloc(tagsize);
5830 cachep->datap = Xmalloc(datasize);
5831
5832 /* fill with bad data for debug */
5833 for (i=(tagsize/8)-1; i>=0; i--) {
5834 cachep->tagp[i] = 0xbaadfeed;
5835 }
5836 for (i=(datasize/8)-1; i>=0; i--) {
5837 cachep->datap[i] = 0xbaadfeed;
5838 }
5839
5840 cachep->bist_ctl = 0;
5841 cachep->assocdis = 0;
5842 cachep->inst_mask = 0;
5843 RW_lock_init(&cachep->rwlock, NULL);
5844}
5845
5846
5847
5848 /****************************************************************
5849 *
5850 * Misc debugging code
5851 *
5852 ****************************************************************/
5853
5854
5855#if !defined(NDEBUG) /* { */
5856
5857
5858#endif /* } */
5859
5860#if defined(NIAGARA1) || defined(NIAGARA2)
5861/*
5862 * called in response to ~i or ~d
5863 */
5864void _ss_dump_tlbs(config_proc_t * config_procp, bool_t is_dtlb, bool_t lockit)
5865{
5866#if !defined(NDEBUG) /* { */
5867 ss_proc_t * np;
5868 uint_t i, pnum;
5869 FILE * fop = stdout;
5870
5871 np = (ss_proc_t*)(config_procp->procp);
5872 pnum = config_procp->proc_id;
5873
5874 if (is_dtlb) {
5875 for (i=0; i<np->ndtlb; i++) {
5876 fprintf(fop, "Processor %u Core %u D-TLB:\n",pnum,i);
5877 ss_tlb_contents(fop, &(np->dtlbp[i]), lockit);
5878 }
5879 } else {
5880 for (i=0; i<np->nitlb; i++) {
5881 fprintf(fop, "Processor %u Core %u I-TLB:\n",pnum,i);
5882 ss_tlb_contents(fop, &(np->itlbp[i]), lockit);
5883 }
5884 }
5885#endif /* } */
5886}
5887
5888void ss_dump_tlbs(config_proc_t * config_procp, bool_t is_dtlb)
5889{
5890 _ss_dump_tlbs(config_procp, is_dtlb, true);
5891}
5892
5893void ss_dump_tlbs_nolock(config_proc_t * config_procp, bool_t is_dtlb)
5894{
5895 _ss_dump_tlbs(config_procp, is_dtlb, false);
5896}
5897#endif
5898
5899
5900
5901#if !defined(NDEBUG) /* { */
5902
5903
5904
5905
5906
5907 /* HACK !! */
5908
5909#include <stdarg.h>
5910
5911typedef enum {
5912PS_Left, PS_Center, PS_Right
5913} just_t;
5914
5915void pspace(FILE * fop, uint_t space, just_t just, char * fmt, ...)
5916{
5917 va_list args;
5918 char buf[2048];
5919 size_t len;
5920 int i, before, after;
5921
5922 va_start(args, fmt);
5923
5924 vsprintf(buf, fmt, args);
5925
5926 va_end(args);
5927
5928 len = strlen(buf);
5929 switch(just) {
5930 case PS_Left:
5931 before = 0;
5932 after = space - len;
5933 if (after<0) after = 0;
5934 break;
5935 case PS_Right:
5936 after = 0;
5937 before = space - len;
5938 if (before<0) before = 0;
5939 break;
5940 case PS_Center:
5941 before = space - len;
5942 if (before<0) before = 0;
5943 before >>=1;
5944 after = space - (len + before);
5945 if (after<0) after = 0;
5946 break;
5947 }
5948
5949 for (i=0; i<before; i++) fprintf(fop, " ");
5950 fprintf(fop, "%s", buf);
5951 for (i=0; i<after; i++) fprintf(fop, " ");
5952}
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962void ss_tlb_contents(FILE *fop, ss_tlb_t * tlbp, bool_t lockit)
5963{
5964 uint_t i;
5965 tlb_entry_t * tep;
5966
5967 pspace(fop, 6, PS_Left, "Entry");
5968 pspace(fop, 8, PS_Right, "Part:");
5969 pspace(fop, 8, PS_Left, "ctxt");
5970 pspace(fop, 7, PS_Center, "shift");
5971 pspace(fop, 20, PS_Center, "Tag");
5972 pspace(fop, 20, PS_Center, "PA");
5973 pspace(fop, 7, PS_Center, "Flags");
5974 pspace(fop, 20, PS_Center, "RAW");
5975 fprintf(fop, "\n");
5976
5977 /* grab lock as writer to ensure nothing changes */
5978 if (lockit)
5979 RW_wrlock(&tlbp->rwlock);
5980
5981 tep = &(tlbp->tlb_entryp[0]);
5982 for (i=0; i<tlbp->nentries; i++) {
5983 char * contextp;
5984 uint_t sh;
5985 tpaddr_t pa;
5986
5987 switch (tep->match_context) {
5988 case SS_TLB_INVALID_CONTEXT:
5989 goto no_output;
5990 case SS_TLB_REAL_CONTEXT:
5991 pspace(fop, 6, PS_Right, "%u : ", i);
5992 pspace(fop, 8, PS_Right, "0x%x:", tep->partid);
5993 pspace(fop, 8, PS_Left, "real");
5994 break;
5995 default:
5996 pspace(fop, 6, PS_Right, "%u : ", i);
5997 pspace(fop, 8, PS_Right, "0x%x:", tep->partid);
5998 pspace(fop, 8, PS_Left, "0x%x", tep->tag_context);
5999 break;
6000 }
6001
6002 pspace(fop, 7, PS_Center, "%u", tep->match_shift);
6003
6004 sh = tep->match_shift;
6005 pa = tep->tag_pfn + tep->pa_offset;
6006
6007 pspace(fop, 20, PS_Right, "0x%llx", tep->tag_pfn);
6008 pspace(fop, 20, PS_Right, "0x%llx", pa);
6009
6010#ifdef NIAGARA1
6011 pspace(fop, 7, PS_Center, "%c%c%c%c%c",
6012 (tep->flags & SS_TLB_FLAG_READ) ? 'R' : '.',
6013 (tep->flags & SS_TLB_FLAG_WRITE) ? 'W' : '.',
6014 (tep->flags & SS_TLB_FLAG_EXEC) ? 'X' : '.',
6015 (tep->flags & SS_TLB_FLAG_PRIV) ? 'P' : '.',
6016 (tep->flags & SS_TLB_FLAG_LOCKED) ? 'L' : '.' );
6017#else
6018 pspace(fop, 7, PS_Center, "%c%c%c%c",
6019 (tep->flags & SS_TLB_FLAG_READ) ? 'R' : '.',
6020 (tep->flags & SS_TLB_FLAG_WRITE) ? 'W' : '.',
6021 (tep->flags & SS_TLB_FLAG_EXEC) ? 'X' : '.',
6022 (tep->flags & SS_TLB_FLAG_PRIV) ? 'P' : '.');
6023#endif
6024 pspace(fop, 20, PS_Right, "0x%llx", tep->data);
6025
6026next:;
6027 fprintf(fop, "\n");
6028no_output:;
6029
6030 tep++;
6031 }
6032 if (lockit)
6033 RW_unlock(&tlbp->rwlock);
6034}
6035
6036#endif /* } */
6037
6038
6039 /****************************************************************
6040 *
6041 * OLD STUFF
6042 *
6043 ****************************************************************/
6044
6045
6046
6047
6048
6049#if 0 /* { */
6050--
6051--void ss_xdc_load_miss(simcpu_t * sp, uint64_t * regp, xdcache_line_t * xclp, tvaddr_t va, bool_t issigned, int bytes)
6052--{
6053-- tpaddr_t pa, pa_tag;
6054-- uint8_t * bufp, * ptr;
6055-- tvaddr_t tag;
6056-- config_dev_t * cdp;
6057-- tpaddr_t extent;
6058-- uint64_t val;
6059-- sparcv9_cpu_t * v9p;
6060-- ss_strand_t * nsp;
6061-- int flags;
6062--
6063-- ASSERT( (bytes & (bytes-1)) == 0 ); /* must be power of 2 number of bytes */
6064--
6065-- v9p = (sparcv9_cpu_t *)(sp->specificp);
6066-- nsp = v9p->impl_specificp;
6067--
6068-- /* quick check of alignment */
6069-- if ((va & (bytes-1)) != 0) {
6070-- /* alignment error force a trap */
6071-- SET_DTLB_LOAD_FAULT( nsp, va );
6072-- MEMORY_ACCESS_TRAP();
6073-- v9p->post_precise_trap(sp, Sparcv9_trap_mem_address_not_aligned);
6074-- return;
6075-- }
6076--
6077-- /* Find the pa corresponding to the line we need */
6078-- tag = va & XDCACHE_TAG_MASK;
6079--
6080-- /* We assume that for Niagara, the TLB is off in Hyper priv mode */
6081-- /* FIXME: we should probably do this by swizzling a function pointer */
6082-- /* for this when we change mode, rather that having an if here ... fix later */
6083--
6084-- pa = va;
6085-- pa_tag = tag;
6086-- if (!nsp->mmu_bypass) {
6087-- int idx, context, partid;
6088-- ss_tlb_t * tlbp;
6089-- tlb_entry_t * tep;
6090-- int flags;
6091--
6092-- tlbp = nsp->dtlbp;
6093-- RW_rdlock(&tlbp->rwlock);
6094--
6095-- /* FIXME: need a current context variable, not a test here */
6096-- context = (v9p->tl>0) ? 0 : nsp->pri_context;
6097-- partid = nsp->partid;
6098--
6099-- /* FIXME: Need a better hash than this ! */
6100-- idx = va >> SS_MAX_PAGE_SIZE_BITS;
6101-- idx += context + partid;
6102--
6103-- idx &= SS_TLB_HASH_MASK;
6104--
6105-- /*
6106-- * So we search for a matching page using the info we have in the
6107-- * hash - while another thread might possibly be removing or
6108-- * inserting an entry into the same table.
6109-- */
6110--
6111--
6112-- for ( tep = tlbp->hash[idx].ptr; tep!=(tlb_entry_t*)0; tep = tep->nextp ) {
6113-- /* try and match the entry as appropriate */
6114-- if (((tep->tag_pfn ^ va)>>tep->match_shift)==0 && tep->match_context==context && tep->partid == partid) goto tlb_match;
6115-- }
6116-- RW_unlock(&tlbp->rwlock);
6117-- SET_DTLB_LOAD_FAULT( nsp, va );
6118-- MEMORY_ACCESS_TRAP();
6119-- v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_fast_data_access_MMU_miss);
6120-- return;
6121--
6122--tlb_match:;
6123-- /* we have a matching entry ... now all we have to worry about are the permissions */
6124-- flags = tep->flags;
6125-- pa += tep->pa_offset;
6126-- pa_tag += tep->pa_offset;
6127--
6128-- RW_unlock(&tlbp->rwlock);
6129--
6130-- if ((flags & SS_TLB_FLAG_PRIV) && v9p->state == V9_User) {
6131-- SET_DTLB_LOAD_FAULT( nsp, va );
6132-- MEMORY_ACCESS_TRAP();
6133-- v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_data_access_exception);
6134-- return;
6135-- }
6136-- }
6137--
6138-- /*
6139-- * OK - now go get the pointer to the line data
6140-- * ... start by finding the device that has the
6141-- * memory we need.
6142-- * optimise: by guessing at the last device found.
6143-- */
6144--
6145-- /* now find the device - looking in the cache first */
6146--
6147-- cdp = sp->xdc.miss_devp;
6148-- if (!(cdp && cdp->baseaddr<=pa && pa<cdp->topaddr)) {
6149-- domain_t * domainp;
6150-- config_proc_t * config_procp;
6151--
6152-- config_procp = sp->config_procp;
6153-- domainp = config_procp->domainp;
6154--
6155-- cdp = find_domain_device(domainp, pa);
6156-- if (cdp == (config_dev_t*)0) {
6157-- /* OK it's a bus error there was no backing store */
6158--
6159-- fatal("bus error - (@pc=0x%llx) load from va=0x%llx (cacheline va=0x%llx -> physical 0x%llx)", sp->pc, va, tag, pa_tag); /* FIXME */
6160-- }
6161-- }
6162--
6163-- /* try and get the buffer pointer */
6164--
6165-- extent = cdp->dev_typep->dev_cacheable(cdp, DA_Load, pa_tag - cdp->baseaddr, &bufp);
6166--
6167-- if (extent < XDCACHE_LINE_SIZE) {
6168-- /* Let device handle memory access operation */
6169-- /* bus error again ? or fill from multiple devices ? */
6170-- /* need to check validty for device here ... FIXME */
6171-- if (cdp->dev_typep->dev_cpu_load(cdp, pa - cdp->baseaddr, issigned, bytes, regp)) goto load_done;
6172--
6173-- MEMORY_ACCESS_TRAP();
6174-- v9p->post_precise_trap(sp, Sparcv9_trap_data_access_error); /* FIXME: right trap ? */
6175-- return;
6176-- }
6177--
6178-- /*
6179-- * For now only handle cacheable device memory
6180-- */
6181-- /* only cache if memory is cacheable */
6182-- sp->xdc.miss_devp = cdp; /* cache for next time */
6183--
6184-- /* fill in the line */
6185-- xclp->tag = tag;
6186-- xclp->offset = ((uint64_t)bufp) - tag;
6187--
6188-- /*
6189-- * Sigh now complete the load on behalf of the original
6190-- * load instruction
6191-- */
6192--
6193-- ptr = (uint8_t*)(xclp->offset + va);
6194--
6195-- if (issigned) {
6196-- switch(bytes) {
6197-- case 1: val = *(sint8_t*)ptr; break;
6198-- case 2: val = *(sint16_t*)ptr; break;
6199-- case 4: val = *(sint32_t*)ptr; break;
6200-- default: abort();
6201-- }
6202-- } else {
6203-- switch(bytes) {
6204-- case 1: val = *(uint8_t*)ptr; break;
6205-- case 2: val = *(uint16_t*)ptr; break;
6206-- case 4: val = *(uint32_t*)ptr; break;
6207-- case 8: val = *(uint64_t*)ptr; break;
6208-- default: abort();
6209-- }
6210-- }
6211--
6212-- *regp = val;
6213--
6214-- /*
6215-- * Finally go get the next instruction
6216-- */
6217--load_done:;
6218--
6219-- NEXT_INSTN(sp);
6220--}
6221--
6222--
6223--
6224--void ss_xdc_store_miss(simcpu_t * sp, uint64_t val, xdcache_line_t * xclp, tvaddr_t va, int bytes)
6225--{
6226-- tpaddr_t pa, pa_tag;
6227-- uint8_t * bufp, * ptr;
6228-- tvaddr_t tag;
6229-- config_dev_t * cdp;
6230-- tpaddr_t extent;
6231-- sparcv9_cpu_t * v9p;
6232-- ss_strand_t * nsp;
6233--
6234-- ASSERT( (bytes & (bytes-1)) == 0 ); /* must be power of 2 number of bytes */
6235--
6236-- v9p = (sparcv9_cpu_t *)(sp->specificp);
6237-- nsp = v9p->impl_specificp;
6238--
6239-- /* quick check of alignment */
6240-- if ((va & (bytes-1)) != 0) {
6241-- /* alignment error force a trap */
6242-- SET_DTLB_STORE_FAULT( nsp, va );
6243-- v9p->post_precise_trap(sp, Sparcv9_trap_mem_address_not_aligned);
6244-- return;
6245-- }
6246--
6247-- /* Find the pa corresponding to the line we need */
6248-- tag = va & XDCACHE_TAG_MASK;
6249--
6250-- /* We assume that for Niagara, the TLB is off in Hyper priv mode */
6251-- /* FIXME: we should probably do this by swizzling a function pointer */
6252-- /* for this when we change mode, rather that having an if here ... fix later */
6253--
6254-- pa = va;
6255-- pa_tag = tag;
6256-- if (!nsp->mmu_bypass) {
6257-- int idx, context, partid;
6258-- ss_tlb_t * tlbp;
6259-- tlb_entry_t * tep;
6260-- int flags;
6261--
6262-- tlbp = nsp->dtlbp;
6263-- RW_rdlock(&tlbp->rwlock);
6264--
6265-- /* FIXME: need a current context variable, not a test here */
6266-- context = (v9p->tl>0) ? 0 : nsp->pri_context;
6267-- partid = nsp->partid;
6268--
6269-- /* FIXME: Need a better hash than this ! */
6270-- idx = va >> SS_MAX_PAGE_SIZE_BITS;
6271-- idx += context + partid;
6272--
6273-- idx &= SS_TLB_HASH_MASK;
6274--
6275-- /*
6276-- * So we search for a matching page using the info we have in the
6277-- * hash - while another thread might possibly be removing or
6278-- * inserting an entry into the same table.
6279-- */
6280--
6281--
6282-- for ( tep = tlbp->hash[idx].ptr; tep!=(tlb_entry_t*)0; tep = tep->nextp ) {
6283-- /* try and match the entry as appropriate */
6284-- if (((tep->tag_pfn ^ va)>>tep->match_shift)==0 && tep->match_context==context && tep->partid == partid) goto tlb_match;
6285-- }
6286-- RW_unlock(&tlbp->rwlock);
6287-- SET_DTLB_STORE_FAULT( nsp, va );
6288-- MEMORY_ACCESS_TRAP();
6289-- v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_fast_data_access_MMU_miss);
6290-- return;
6291--
6292--tlb_match:;
6293-- /* we have a matching entry ... now all we have to worry about are the permissions */
6294-- flags = tep->flags;
6295-- pa += tep->pa_offset;
6296-- pa_tag += tep->pa_offset;
6297--
6298-- RW_unlock(&tlbp->rwlock);
6299--
6300-- /* privilege test apparently takes priority ... p.51 US-I PRM table 6-4 */
6301-- if ((flags & SS_TLB_FLAG_PRIV) && v9p->state == V9_User) {
6302-- SET_DTLB_STORE_FAULT( nsp, va );
6303-- MEMORY_ACCESS_TRAP();
6304-- v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_data_access_exception);
6305-- return;
6306-- }
6307--
6308-- if (!(flags & SS_TLB_FLAG_WRITE)) {
6309-- SET_DTLB_STORE_FAULT( nsp, va );
6310-- MEMORY_ACCESS_TRAP();
6311-- v9p->post_precise_trap(sp, (sparcv9_trap_type_t)SS_trap_fast_data_access_protection);
6312-- return;
6313-- }
6314-- }
6315--
6316--
6317-- /*
6318-- * OK - now go get the pointer to the line data
6319-- * ... start by finding the device that has the
6320-- * memory we need.
6321-- * optimise: by guessing at the last device found.
6322-- */
6323--
6324-- /* now find the device - looking in the cache first */
6325--
6326-- cdp = sp->xdc.miss_devp;
6327-- if (!(cdp && cdp->baseaddr<=pa && pa<cdp->topaddr)) {
6328-- domain_t * domainp;
6329-- config_proc_t * config_procp;
6330--
6331-- config_procp = sp->config_procp;
6332-- domainp = config_procp->domainp;
6333--
6334-- cdp = find_domain_device(domainp, pa);
6335-- if (cdp == (config_dev_t*)0) {
6336-- /* OK it's a bus error there was no backing store */
6337--
6338-- fatal("bus error - (@pc=0x%llx) store to va=0x%llx (cacheline va=0x%llx -> physical 0x%llx)", sp->pc, va, tag, pa); /* FIXME */
6339-- }
6340-- }
6341--
6342-- /* try and get the buffer pointer */
6343--
6344-- extent = cdp->dev_typep->dev_cacheable(cdp, DA_Store, pa_tag - cdp->baseaddr, &bufp);
6345--
6346-- if (extent < XDCACHE_LINE_SIZE) {
6347-- /* Let device handle memory access operation */
6348-- /* bus error again ? or fill from multiple devices ? */
6349-- /* need to check validty for device here ... FIXME */
6350-- if (cdp->dev_typep->dev_cpu_store(cdp, pa - cdp->baseaddr, bytes, val)) goto store_done;
6351--
6352-- MEMORY_ACCESS_TRAP();
6353-- v9p->post_precise_trap(sp, Sparcv9_trap_data_access_error); /* FIXME: right trap ? */
6354-- return;
6355-- }
6356--
6357-- /*
6358-- * For now only handle cacheable device memory
6359-- */
6360-- /* only cache if memory is cacheable */
6361-- sp->xdc.miss_devp = cdp; /* cache for next time */
6362--
6363-- /* fill in the line */
6364-- xclp->tag = tag;
6365-- xclp->offset = ((uint64_t)bufp) - tag;
6366--
6367-- /*
6368-- * Sigh now complete the store on behalf of the original
6369-- * store instruction
6370-- */
6371--
6372-- ptr = (uint8_t*)(xclp->offset + va);
6373--
6374-- switch(bytes) {
6375-- case 1: *(uint8_t*)ptr = val; break;
6376-- case 2: *(uint16_t*)ptr = val; break;
6377-- case 4: *(uint32_t*)ptr = val; break;
6378-- case 8: *(uint64_t*)ptr = val; break;
6379-- default: abort();
6380-- }
6381--
6382--
6383-- /*
6384-- * Finally go get the next instruction
6385-- */
6386--store_done:;
6387--
6388-- NEXT_INSTN(sp);
6389--}
6390--
6391--
6392#endif /* } */
6393
6394
6395/*
6396 * called in response to ~n
6397 */
6398void ss_dump_instruction_counts(config_proc_t * cp)
6399{
6400#if !defined(NDEBUG) /* { */
6401 ss_proc_t * np;
6402 sparcv9_cpu_t * sv9p;
6403#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
6404 ss_strand_t * nsp;
6405#endif /* } */
6406 simcpu_t * sp;
6407 uint64_t hi_cycle = 0;
6408 uint64_t lo_cycle = 0xFFFFFFFFFFFFFFFF;
6409 uint64_t now;
6410 uint_t j;
6411 uint_t ncpus;
6412
6413 np = (ss_proc_t*)(cp->procp);
6414
6415 ncpus = np->nstrands;
6416 if (ncpus > 1)
6417 lprintf(-1, "==== strand counts proc %d ====\n", cp->proc_id);
6418 for (j=0; j<ncpus; j++) {
6419 sv9p = np->strand[j];
6420 sp = sv9p->simp;
6421 now = sp->cycle;
6422
6423 if (now > hi_cycle)
6424 hi_cycle = now;
6425 if (now < lo_cycle)
6426 lo_cycle = now;
6427 lprintf(sp->gid, "@ pc=0x%llx tl=%d: cycle[%llu] instr[%llu] "
6428 "cycle_target[%lld] \n",
6429 sp->pc, sv9p->tl, sp->cycle, ICOUNT(sp),
6430 sp->cycle_target);
6431
6432#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
6433 nsp = sv9p->impl_specificp;
6434 if (nsp->pcr != 0 || nsp->pic0 != 0 || nsp->pic1 != 0) {
6435 lprintf(sp->gid, "%%pcr=0x%llx %%pic0=0x%x "
6436 "%%pic1=0x%x\n",
6437 nsp->pcr, nsp->pic0, nsp->pic1);
6438 }
6439#endif /* } */
6440
6441 }
6442 if (ncpus > 1)
6443 lprintf(sp->gid, "hi_cycle - lo_cycle=%llu\n", hi_cycle - lo_cycle);
6444
6445#endif /* } */
6446}
6447
6448/*
6449 * This function is called upon each update to the running status register.
6450 * It performs a bit test (each bit corresponding to a virtual core or strand)
6451 * and park or unpark the corresponding strand depending on the bit value.
6452 */
6453void
6454ss_change_exec_state(ss_proc_t *npp, uint64_t running_status)
6455{
6456 uint_t idx, ncpu, vcore_id;
6457
6458 ncpu = npp->nstrands;
6459
6460 for (idx = 0; idx < ncpu; idx++) {
6461 sparcv9_cpu_t *tv9p;
6462 simcpu_t *tsp;
6463 ss_strand_t *tnsp;
6464 uint_t unparked;
6465
6466 tnsp = &(npp->ss_strandp[idx]);
6467 tv9p = npp->strand[idx];
6468 tsp = tv9p->simp;
6469
6470 vcore_id = tnsp->vcore_id;
6471 unparked = ((running_status >> vcore_id) & 0x1);
6472
6473 if (unparked) {
6474#if defined(NIAGARA1) /* { */
6475 SET_THREAD_STS_SFSM(npp, tnsp, THREAD_STS_TSTATE_RUN);
6476#endif /* } NIAGARA1 */
6477 if (PARKED(tsp))
6478 simcore_cpu_state_unpark(tsp);
6479 } else {
6480#if defined(NIAGARA1) /* { */
6481 SET_THREAD_STS_SFSM(npp, tnsp, THREAD_STS_TSTATE_IDLE);
6482#endif /* } NIAGARA1 */
6483 if (!PARKED(tsp))
6484 simcore_cpu_state_park(tsp);
6485 }
6486 }
6487}
6488
6489/*
6490 * Given a PA from hypervisor, lookup where in simualted
6491 * memory that PA resides so we can read an address
6492 * local to the simulator.
6493 */
6494uint64_t* lookup_sim_addr(simcpu_t *sp, uint64_t *sim_addr)
6495{
6496 uint64_t extent;
6497 config_addr_t *cap;
6498 domain_t *domainp;
6499 config_proc_t *config_procp;
6500 uint64_t *bufp;
6501
6502 config_procp = sp->config_procp;
6503 domainp = config_procp->domainp;
6504
6505 /*
6506 * Lookup which memory device owns this address
6507 * XXX FIXME: We know it's in memory, so we could cache it here
6508 */
6509 cap = find_domain_address(domainp, (tpaddr_t)sim_addr);
6510 if (cap == NULL) {
6511 /* it's a bus error there was no backing store */
6512 EXEC_WARNING(("bus error - (@pc=0x%llx, icount=%llu) access to addr=0x%llx ",
6513 sp->pc, ICOUNT(sp), sim_addr));
6514 abort();
6515 }
6516
6517 /*
6518 * Use the device function to read the memory address
6519 */
6520 extent = cap->config_devp->dev_typep->dev_cacheable(cap, DA_Load,
6521 (uint64_t)sim_addr - cap->baseaddr, (uint8_t **)&bufp);
6522 ASSERT(extent != 0);
6523
6524 return(bufp);
6525}
6526
6527
6528/*
6529 * Get the virtual core Id (or CPU Id) of the calling strand.
6530 */
6531uint_t ss_get_cpuid(simcpu_t *sp)
6532{
6533 sparcv9_cpu_t *v9p;
6534 ss_strand_t *nsp;
6535
6536 v9p = (sparcv9_cpu_t *)(sp->specificp);
6537 nsp = v9p->impl_specificp;
6538
6539 return (nsp->vcore_id);
6540}
6541
6542/*
6543 * Being used when switching to SST mode to simulate CPU's behaviour
6544 * of trashing all registers.
6545 */
6546void ss_trash_regs(sparcv9_cpu_t * v9p, uint64_t val)
6547{
6548 simcpu_t * sp;
6549 uint_t idx;
6550
6551 sp = v9p->simp;
6552
6553 /* trash globals */
6554 for (idx = 0; idx < v9p->nglobals * 8; idx++){
6555 /* need to leave %g0 alone */
6556 if (idx % 8)
6557 v9p->globalsp[idx] = val;
6558 }
6559
6560 /* trash ins and locals */
6561 for (idx = 0; idx < (v9p->nwins * 2 * V9_REG_GROUP); idx++)
6562 v9p->winsp[idx] = val;
6563
6564 /* trash floating point regs */
6565 for (idx = 0; idx < NFP_64; idx++)
6566 sp->fpreg.s64[idx] = val;
6567
6568 /* trash what's in the working register file */
6569 for (idx = 1; idx < NINT; idx++)
6570 sp->intreg[idx] = val;
6571}
6572
6573 /*
6574 * Macro to create symbols for the debug_hook functions
6575 */
6576#define ADD_DBG_DEFS( func ) extern void dbg_##func##(simcpu_t *sp, uint32_t rawi);\
6577 extern void dbg_##func##_parse(void); \
6578 extern void dbg_##func##_dump(void)
6579 ADD_DBG_DEFS(trace);
6580 ADD_DBG_DEFS(coverage);
6581 ADD_DBG_DEFS(debug_log);
6582 ADD_DBG_DEFS(lockstep);
6583
6584 /*
6585 * Parse the debug_hook directive.
6586 * The debug_hook directive in the conf file should look like this:
6587 *
6588 * directive_name debug_hook .....
6589 * -------------- ----------
6590 * eg:
6591 * debug_hook trace ..... ;
6592 * \________________________/ \____________/
6593 * we parse this much here debug_hook_parse()
6594 * parses the rest if any
6595 *
6596 * We parse the 'debug_hook' as the name of the function the user
6597 * is requesting. We then use this name to locate the following functions:
6598 * debug_hook - execloop calls this for each instn
6599 * debug_hook_parse - we call this to parse the rest of the directive
6600 * debug_hook_dump - dumbserial calls this when ~l is input on
6601 * the console
6602 *
6603 */
6604
6605static void parse_debug_hook(ss_proc_t *procp)
6606{
6607 lexer_tok_t tok;
6608 char hookname[BUFSIZ];
6609 char hookname_parse[BUFSIZ];
6610 char hookname_dump[BUFSIZ];
6611 void (*hookp)(uint_t);
6612 void (*hook_parsep)(void);
6613 void (*hook_dumpp)(uint_t);
6614
6615 tok = lex_get_token(); /* parse debug_hook function name */
6616 sprintf(hookname, "%s", lex.strp);
6617 sprintf(hookname_parse, "%s_parse", hookname); /* debug_hook_parse() */
6618 sprintf(hookname_dump, "%s_dump", hookname); /* debug_hook_dump() */
6619
6620 if (streq(hookname, "trace")) {
6621 hookp = (void(*)(uint_t))dbg_trace;
6622 hook_parsep = (void(*)(void))dbg_trace_parse;
6623 hook_dumpp = (void(*)(uint_t))dbg_trace_dump;
6624 } else if (streq(hookname, "coverage")) {
6625 hookp = (void(*)(uint_t))dbg_coverage;
6626 hook_parsep = (void(*)(void))dbg_coverage_parse;
6627 hook_dumpp = (void(*)(uint_t))dbg_coverage_dump;
6628 } else if (streq(hookname, "debug_log")) {
6629 hookp = (void(*)(uint_t))dbg_debug_log;
6630 hook_parsep = (void(*)(void))dbg_debug_log_parse;
6631 hook_dumpp = (void(*)(uint_t))dbg_debug_log_dump;
6632 } else if (streq(hookname, "lockstep")) {
6633 hookp = (void(*)(uint_t))dbg_lockstep;
6634 hook_parsep = (void(*)(void))dbg_lockstep_parse;
6635 hook_dumpp = (void(*)(uint_t))dbg_lockstep_dump;
6636 } else {
6637 lex_fatal("Unsupported debug_hook %s", hookname);
6638 }
6639
6640 procp->config_procp->proc_typep->debug_hookp = (void*)hookp;
6641 procp->config_procp->proc_typep->debug_hook_dumpp = (void*)hook_dumpp;
6642
6643 /*
6644 * Now call the parse function to continue parsing the
6645 * debug_hook directive.
6646 */
6647 hook_parsep();
6648
6649 lex_get(T_S_Colon);
6650
6651 return;
6652}
6653
6654#define PRI_CTX_IS_NUCLEUS(_nsp) ((_nsp)->pri_context == SS_NUCLEUS_CONTEXT)
6655
6656void
6657xcache_set_tagstate(simcpu_t * sp)
6658{
6659 ss_strand_t * nsp;
6660 sparcv9_cpu_t * v9p;
6661 uint32_t newstate;
6662
6663 v9p = (sparcv9_cpu_t *)(sp->specificp);
6664 nsp = v9p->impl_specificp;
6665
6666 if (nsp->mmu_bypass)
6667 newstate = XCACHE_TAGSTATE_PHYS;
6668 else
6669 if (v9p->state == V9_User) {
6670 newstate = (v9p->tl == 0 && !PRI_CTX_IS_NUCLEUS(nsp)) ?
6671 XCACHE_TAGSTATE_TL0_U : XCACHE_TAGSTATE_TLN_U;
6672 }
6673 else {
6674 newstate = (v9p->tl == 0 && !PRI_CTX_IS_NUCLEUS(nsp)) ?
6675 XCACHE_TAGSTATE_TL0 : XCACHE_TAGSTATE_TLN;
6676 }
6677 DBGXCACHE( lprintf(sp->gid, "xcache_set_tagstate: %u -> %u "
6678 "pc=0x%llx [cycle=0x%llx]\n",
6679 sp->tagstate >> _XCACHE_TAGSTATE_SHIFT,
6680 newstate >> _XCACHE_TAGSTATE_SHIFT, sp->pc, sp->cycle); );
6681
6682 if (sp->tagstate != newstate)
6683 sp->exec_loop_reset = true;
6684
6685 sp->tagstate = newstate;
6686}
6687
6688void
6689ss_rdlock(RW_lock_t *lp)
6690{
6691 RW_lock_t l, n, v;
6692
6693again:
6694 while ((l = *lp) < 0)
6695 ;
6696 n = l + 1;
6697 v = host_cas64((uint64_t *)lp, l, n);
6698 if (v != l)
6699 goto again;
6700}
6701
6702
6703void
6704ss_wrlock(RW_lock_t *lp)
6705{
6706 RW_lock_t l, n, v;
6707
6708 n = -1;
6709again:
6710 while ((l = *lp) != 0)
6711 ;
6712 v = host_cas64((uint64_t *)lp, l, n);
6713 if (v != l)
6714 goto again;
6715}
6716
6717
6718void
6719ss_unlock(RW_lock_t *lp)
6720{
6721 RW_lock_t l, n, v;
6722
6723again:
6724 l = *lp;
6725 if (l > 0) {
6726 n = l - 1;
6727 } else
6728 if (l < 0) {
6729 n = 0;
6730 } else
6731 fatal("lock error");
6732 v = host_cas64((uint64_t *)lp, l, n);
6733 if (v != l)
6734 goto again;
6735}
6736
6737/*
6738 * Memory images are written out in 2 formats. Binary format and
6739 * text format. With the binary format, a partial legion config
6740 * file is also dumped which contains the memory directives for
6741 * loading in the various memory binary images.
6742 *
6743 * Memory images are stored in a text file with the following format:
6744 *
6745 * @addr
6746 * 8d41400010800036 0100000000000000 0000000000000000 0000000000000000
6747 * 8d41400010800036 0100000000000000 0000000000000000 0000000000000000
6748 * 8d4140008c21a020 1080002601000000 108004e601000000 0000000000000000
6749 * 1080052901000000 0000000000000000 0000000000000000 0000000000000000
6750 * 1080056b01000000 0000000000000000 0000000000000000 0000000000000000
6751 * 108005aa01000000 0000000000000000 0000000000000000 0000000000000000
6752 * 108005e901000000 0000000000000000 0000000000000000 0000000000000000
6753 * 03004000c221a000 c221a004c221a008 c221a00c10800240 0100000082102018
6754 * @addr//+size
6755 *
6756 * where :
6757 * @addr is the starting address of a chunk of memory followed by
6758 * a mimimum of 256 bytes of non-zero data.
6759 *
6760 * If a range of memory is all zeroes, it is recorded as:
6761 * @addr//+size
6762 */
6763void
6764save_memory_segment_axis(config_dev_t *cdp, FILE *filep)
6765{
6766 uint64_t *legion_mem_basep;
6767 uint64_t data_chunk[32];
6768 uint64_t off = 0;
6769 uint64_t foo_addr = 0;
6770 uint64_t skip_cnt = 0;
6771 int i;
6772
6773#define MEM_IMAGE_DATA_SIZE 32
6774
6775 /* Get the base address of the Guest Mem segment */
6776 if (cdp->dev_typep->dev_cacheable(cdp->addrp, DA_Load, 0, (uint8_t**)&legion_mem_basep) == 0)
6777 fatal("Failed to locate base address for memory segment @ 0x%llx\n", cdp);
6778
6779 fprintf(filep, "\n//Memory from %llx to %llx range %llx - %p",
6780 cdp->addrp->baseaddr,
6781 cdp->addrp->topaddr,
6782 cdp->addrp->range,
6783 cdp);
6784
6785
6786 /*
6787 * process memory in 256 byte chunks
6788 */
6789 while (off <= (cdp->addrp->range - 256)) {
6790 bool_t has_data = false;
6791 uint64_t start_addr;
6792 uint64_t legion_addr;
6793
6794 start_addr = cdp->addrp->baseaddr + off;
6795 legion_addr = start_addr;
6796
6797 /*
6798 * Scan a 256 Byte chunk of memory at a time
6799 * and mark it if it has any non-zero data.
6800 */
6801 for (i = 0; i < MEM_IMAGE_DATA_SIZE; i++) {
6802 data_chunk[i] = *legion_mem_basep++;
6803
6804 /*
6805 * apply any memory patch here
6806 */
6807 if (options.save_restore.mem_patch.addr != 0x0) {
6808 if (legion_addr == options.save_restore.mem_patch.addr) {
6809 printf("Patching addr (0x%llx) from 0x%llx to 0x%llx\n",
6810 legion_addr, data_chunk[i],
6811 options.save_restore.mem_patch.val);
6812 data_chunk[i] = options.save_restore.mem_patch.val;
6813 }
6814 }
6815 off += 8;
6816 legion_addr += 8;
6817
6818 if (data_chunk[i] != 0ULL) {
6819 /*
6820 * There's non-zero data in this chunk
6821 * so we flag this so we can print the
6822 * contents of the 256byte chunk.
6823 */
6824 has_data = true;
6825 }
6826 }
6827
6828 /*
6829 * If memory chunk is non-zero, print it
6830 * otherwise, keep a track of zero chunks
6831 * so we can print a summary before the next
6832 * non-zero chunk.
6833 */
6834 if (has_data) {
6835 /* print addr for first chunk of memory */
6836 if (start_addr == cdp->addrp->baseaddr) {
6837 fprintf(filep, "\n@%llx\n", start_addr);
6838 }
6839
6840 /*
6841 * We've got data to print, lets check if we have
6842 * skipped over any zero chunks of memory and print a
6843 * summary of these first.
6844 */
6845 if (skip_cnt != 0) {
6846 fprintf(filep, "\n@%llx//+%llx\n",
6847 foo_addr, skip_cnt * 256);
6848 skip_cnt = 0;
6849 foo_addr = 0x0ULL;
6850
6851 /*
6852 * Now, print the starting @addr of the new
6853 * non-zero chunk
6854 */
6855 fprintf(filep, "\n@%llx\n", start_addr);
6856 }
6857
6858 /* Print the 256 bytes of data */
6859 for (i=0; i< MEM_IMAGE_DATA_SIZE; i++) {
6860 fprintf(filep, "%016llx ", data_chunk[i]);
6861 if ((i & 0x3) == 0x3)
6862 fprintf(filep, "\n");
6863 }
6864
6865 } else {
6866 /* chunk was all zeros so, just keep a count */
6867 if (skip_cnt == 0) {
6868 /* save start address of zero chunk */
6869 foo_addr = start_addr;
6870 }
6871 skip_cnt++;
6872 }
6873 }
6874
6875 /* Before we finish, check if we have any zero chunks to print */
6876 if (skip_cnt != 0) {
6877 fprintf(filep, "\n@%llx//+%llx\n",
6878 foo_addr, skip_cnt * 256);
6879 }
6880}
6881
6882void
6883save_memory_segment_binary(config_dev_t *cdp, FILE *filep)
6884{
6885 uint64_t *legion_mem_basep;
6886 uint64_t *datap;
6887 uint64_t size = cdp->addrp->range;
6888 uint64_t start_addr = cdp->addrp->baseaddr;
6889 uint64_t end_addr = cdp->addrp->baseaddr + size;
6890 char filename[MAXPATHLEN];
6891 int fd = 0;
6892 static int file_cnt = 0;
6893 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
6894
6895 /*
6896 * Open new file
6897 * mmap in new file
6898 * bcopy from legion memory to new file
6899 * unmap file
6900 */
6901 /* Get the base address of the Guest Mem segment */
6902 if (cdp->dev_typep->dev_cacheable(cdp->addrp, DA_Load, 0, (uint8_t**)&legion_mem_basep) == 0)
6903 fatal("Failed to locate base address for memory segment @ 0x%llx\n", cdp);
6904
6905 sprintf(filename, "mem.image.%d", file_cnt++);
6906 lprintf(-1, "Writing %s basep=0x%llx, range=0x%llx (0x%llx)\n",
6907 filename, start_addr, size, legion_mem_basep);
6908
6909 /* if file already exists, delete it */
6910 if (file_exists(filename))
6911 unlink(filename);
6912
6913 /* Open new output file and set size */
6914 if ((fd = open(filename, O_RDWR | O_CREAT, mode)) == -1)
6915 fatal("Error opening %s for writing\n", filename);
6916
6917 /* Set the size of the file by seeking to the end and write NULL */
6918 if (lseek(fd, size-1, SEEK_SET) < 0)
6919 fatal("Could not create file %s of size [0x%llx]",
6920 filename, size);
6921
6922 if (write(fd, "", 1) != 1)
6923 fatal("Could not write to file %s of size [0x%llx]",
6924 filename, size);
6925
6926 /* mmap file file */
6927 datap = (uint64_t*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
6928 if (datap == MAP_FAILED)
6929 fatal("Failed to mmap %s\n", filename);
6930
6931 /* bcopy from legion memory segment to newly mmaped file */
6932 bcopy(legion_mem_basep, datap, size);
6933
6934 /*
6935 * apply any memory patch to the newly created binary
6936 */
6937 if (options.save_restore.mem_patch.addr != 0x0) {
6938
6939 uint64_t *patch_addr;
6940 uint64_t offset;
6941
6942 if ((start_addr <= options.save_restore.mem_patch.addr) &&
6943 (end_addr >= options.save_restore.mem_patch.addr)) {
6944
6945 offset = options.save_restore.mem_patch.addr - start_addr;
6946 patch_addr = (uint64_t *)((uint64_t)datap + (uint64_t)offset);
6947
6948 printf("Patching addr (0x%llx) from 0x%llx to 0x%llx\n",
6949 options.save_restore.mem_patch.addr, *patch_addr,
6950 options.save_restore.mem_patch.val);
6951
6952 /* apply patch */
6953 *patch_addr = options.save_restore.mem_patch.val;
6954 }
6955 }
6956
6957 if (munmap((void*)datap, size) != 0)
6958 fatal("Error munmapping file %s\n", filename);
6959
6960 /* write out legion memory directive to load this back in */
6961 fprintf(filep, "\ndevice \"memory\" 0x%llx +0x%llx {\n" \
6962 " load +0x0 \"%s\"; \n" \
6963 "}\n",
6964 start_addr, size, filename);
6965
6966 close(fd);
6967}
6968
6969
6970bool_t
6971ss_save_state(simcpu_t *sp)
6972{
6973 domain_t *domainp = sp->config_procp->domainp;
6974 config_dev_t *cdp = NULL;
6975 FILE *mem_image_filep = 0;
6976 FILE *config_filep = 0;
6977
6978 if (options.save_restore.legion_format) {
6979
6980 /*
6981 * For legion, we dump out memory images in binary
6982 * format and then print a partial legion config file
6983 * called restore.conf .
6984 * This file contains the memory directives for loading
6985 * these binary memory images back into legion.
6986 */
6987 lprintf(sp->gid, "ss_save_state about to save system memory " \
6988 "in binary format\nWait for Legion to save each memory " \
6989 "image and print a Completed message.\n");
6990
6991 if ((config_filep = fopen("restore.conf", "w")) == NULL)
6992 fatal("Error opening %s for writing\n", "restore.conf");
6993
6994 /* Locate the all memory segments, save them out in binary format */
6995 for (cdp = domainp->device.listp; cdp!=(config_dev_t*)0; cdp=cdp->nextp) {
6996 if (streq(cdp->dev_typep->dev_type_namep, "memory")) {
6997 save_memory_segment_binary(cdp, config_filep);
6998 }
6999 }
7000 fclose(config_filep);
7001
7002 } else {
7003 /*
7004 * For axis, we dump out memory images in txt format
7005 */
7006 lprintf(sp->gid, "ss_save_state about to save system " \
7007 "memory to %s in Axis format\n",
7008 options.save_restore.filenamep);
7009
7010 if ((mem_image_filep =
7011 fopen(options.save_restore.filenamep, "w")) == NULL) {
7012 fatal("Error opening %s for writing\n",
7013 options.save_restore.filenamep);
7014 }
7015
7016 /* Locate the all memory segments, save them to text format */
7017 for (cdp = domainp->device.listp; cdp!=(config_dev_t*)0; cdp=cdp->nextp) {
7018 if (streq(cdp->dev_typep->dev_type_namep, "memory")) {
7019 save_memory_segment_axis(cdp, mem_image_filep);
7020 }
7021 }
7022 fclose(mem_image_filep);
7023 }
7024
7025 return (true);
7026
7027}