1
0
Files
2022-09-29 17:59:04 +03:00

394 lines
12 KiB
C

#ifndef __GENPDA_H__
#define __GENPDA_H__
/*
* genpda.h - multiprocessor-related definitions for arcs programs
*
* genpda.h defines a structure containing all of the
* *generic* global data declared and referenced by arcs
* standalones directly or indirectly via libs{c,k}
* routines, and which therefore must be duplicated on MP
* machines. An array of these pda structures--indexed by
* the virtual processor number allowing sequential
* numbering--provides a largely tranparent, runtime
* solution to the MP-global data problem. SP architectures
* have virtual processor ids hardwired to 0 and use pda
* arrays of size 1, avoiding conditional compilation.
*
* All libsk and libsc routines (most importantly fault.c and
* faultasm.s!) now automatically reference the private copies.
* ide/ide_mp.[ch] illustrate a method for extending the
* arcs pda to include global data that isn't referenced
* outside of the standalone program in which it is declared.
*
* $Revision: 1.32 $
*/
#if EVEREST
#include <sys/EVEREST/everest.h>
#include <sys/EVEREST/evmp.h>
#ifdef LARGE_CPU_COUNT_EVEREST
#define MAXCPU 128
#else
#define MAXCPU EV_MAX_CPUS
#endif
#endif
#if SN
#if _LANGUAGE_C
#include <sys/types.h>
#endif
#include <sys/SN/agent.h>
#include <sys/SN/arch.h>
#ifndef MAXCPU /* we already get this from cpumask.h */
#define MAXCPU MAXCPUS
#endif /* MAXCPU */
#include <fault.h>
#endif /* SN */
#ifdef IP30
#include <sys/RACER/IP30.h>
#endif
#if !defined(MAXCPU)
#define MAXCPU 1
#endif
#if MAXCPU > 1
#define MULTIPROCESSOR 1
#endif
#define YES_EVEREST 0xCAB
#if SN
#define GENERIC_PDASIZE 2048 /* size in bytes of the generic PDA */
#define GENERIC_PDASIZE_2 11 /* log2 of GENERIC_PDASIZE */
#else
#define GENERIC_PDASIZE 512 /* size in bytes of the generic PDA */
#define GENERIC_PDASIZE_2 9 /* log2 of GENERIC_PDASIZE */
#endif
#ifdef _LANGUAGE_C
#include <sys/types.h>
#include <setjmp.h>
/* can have at most 32 instructions */
struct vector10 {
/* R3000 R4000 */
inst_t inst1; /* lui k0,0x???? lui k0,0x???? */
inst_t inst2; /* addu k0,0x???? addu k0,0x???? */
inst_t inst3; /* lw k0,0(k0) lw k0,0(k0) */
inst_t inst4; /* nop nop */
inst_t inst5; /* jal k1,k0 jal k1,k0 */
inst_t inst6; /* nop nop */
inst_t inst7; /* j k0 mtc0 k0,C0_EPC */
inst_t inst8; /* rfe nop */
inst_t inst9; /* nop */
inst_t inst10; /* eret */
};
typedef unsigned long arcs_reg_t;
typedef volatile unsigned long varcs_reg_t;
/*
* Private Data Area for generic global data used by (nearly) all arcs
* standalone programs, primarily pertaining to fault handling.
* In order to provide consistent assembly offsets, the pda includes
* architecturally-specific globals, but they are ignored by the
* fault-handling code via runtime checks.
* The 'specific_pda' field allows standalones to create
* program-specific pdas.
*
* This structure and the offsets defined below must match
* (libsk/ml/faultasm.s assembly routines use them to access the pdas).
*/
typedef union generic_pda_u {
volatile struct generic_pda_s {
varcs_reg_t gpda_magic; /* marks this pda as valid */
varcs_reg_t epc_save; /* pc at the time of the exception */
varcs_reg_t at_save; /* cmplr tromps at & v0; save 'em. */
varcs_reg_t v0_save;
varcs_reg_t badvaddr_save; /* if addr exception this was bad VA */
varcs_reg_t cause_save; /* C0_CAUSE */
varcs_reg_t sp_save; /* save norm sp during faults */
varcs_reg_t sr_save; /* C0_SR at time of exception */
varcs_reg_t exc_save; /* specific handler sets this */
varcs_reg_t stack_mode; /* are we on reg or fault stack now? */
varcs_reg_t mode_save; /* process mode (norm/excep) at fault */
varcs_reg_t my_virtid; /* virtual (contiguous) processor # */
varcs_reg_t my_physid; /* physical (hw-readable) processor # */
varcs_reg_t notfirst;
varcs_reg_t first_epc;
varcs_reg_t retn_addr_save; /* Save return address of exc hndlr */
varcs_reg_t *pda_initial_sp; /* stores sp during process startup */
varcs_reg_t *pda_fault_sp; /* pts to fault-handling stack */
k_machreg_t *regs; /* saved user_state during exception */
jmpbufptr pda_nofault;
varcs_reg_t cache_err_save; /* decodes location & type of ECC err */
varcs_reg_t error_epc_save; /* if ECC exception, this was the pc */
/* symmon specific entries from old symmon pda */
/* NOTE that a k_machreg_t is 8 bytes on EVEREST systems.
* Hence there could be an alignment pad between _sv_gp
* and its predecessor - currently there is not such an
* alignment pad, but beware of adding stuff to
* this struct before _sv_gp.
*/
/* These are arranged so that the largest entries come first -
* k_machreg_t, since that is currently 64 bits on everest, then
* next largest - ptrs, since those are 64 bits on 64 bit kernels,
* then ints. This makes figuring the constant offsets for
* assembler below easier, since you don't have to deal with
* alignment gaps, etc.
* Only those elements that are used by assemble code are
* arranged in this way. Currently, dbg_exc is the last one.
*/
k_machreg_t _sv_gp;
k_machreg_t _sv_ra;
k_machreg_t _sv_k1;
k_machreg_t _symmon_sv_at; /* Slightly redundant with _at_sv
* above, but this one is a
* k_machreg_t.
*/
int *dbg_stack; /* dbgmon stack */
k_machreg_t *exc_stack; /* ptr to exc stack frame */
int dbg_mode; /* MODE_DBGMON,MODE_CLIENT,MODE_IDBG */
int dbg_modesav;
int dbg_exc; /* EXCEPT_NORM, UTLB, BRKPT */
/* end of symmon fields that are used in assembly files */
jmpbufptr _restart_buf; /* ptr to jmp_buf to get to _dbgmon */
jmpbufptr bp_nofault;
k_machreg_t *sregs; /* copy of regs when in idbg mode */
jmpbufptr step_jmp;
int step_flag;
int step_count; /* for step commands */
int (*step_routine)(int);
__psunsigned_t noffst;
char *cbuf; /* buffer for char input processing */
int column; /* current console output column */
int saved;
void (*volatile launch)(void *); /* routine to execute */
void *launch_arg; /* arg to this routine */
#if TFP
__psint_t save_trapbase[4];
__psint_t save_gevector[4];
__psint_t save_utlbvector[4];
#else
inst_t *save_utlb[4];
inst_t *save_norm[4];
inst_t *save_xtlb[4];
#endif
char nmi_int_flag; /* NMI seen on cpu */
#if SN
struct vector10 p_nmi_save_utlb[4];
struct vector10 p_nmi_save_norm[4];
struct vector10 p_nmi_save_xut[4];
struct vector10 p_nmi_save_ecc[4];
uint p_nmi_save_gevector[4];
uint p_nmi_save_utlbvector[4];
uint p_nmi_saved;
k_machreg_t excep_regs[NREGS];
#endif
} gdata;
char filler[GENERIC_PDASIZE]; /* any reasonable power of 2 */
} gen_pda_t;
#define GPDA_MAGIC 0xadacab
#ifdef SN
extern gen_pda_t *gen_pda_tabp[];
#define GEN_PDA_TAB(vid) (*gen_pda_tabp[vid])
#else
extern gen_pda_t gen_pda_tab[];
#define GEN_PDA_TAB(vid) gen_pda_tab[vid]
#endif
#endif /* _LANGUAGE_C */
#if (_USE_FULL_PATH != 0xfeed)
#define _USE_PPTR 0xcad
#include <fault.h>
/*
* Files which explicitly include genpda.h can reference the fields
* of pda structures with ptrs or use the GPRIVATE and GPME macros
* to do so. They cannot, however, reference the global variables
* (which in reality are fields in arrays of pda structs) simply by
* name.
* Files which include fault.h can access the global variables
* by name--blithely unaware of the underlying pda structure--but
* therefore cannot explicitly reference any pda fields.
* Note that the idempotentcy (#define) protection in both headers
* prevents double-inclusion problems; the above ordering, however,
* is a crucial requirement.
*/
#ifdef _LANGUAGE_C
#define _cpuid() cpuid()
/*
* The GPRIVATE macro provides explicit access to the fields in
* "vid"'s pda, and GPME accesses the processor's own pda.
*/
#define GPRIVATE(_VID,_FIELD) (GEN_PDA_TAB(_VID).gdata._FIELD)
#define GPME(_FIELD) (GEN_PDA_TAB(_cpuid()).gdata._FIELD)
#endif /* !_LANGUAGE_ASSEMBLY */
#undef _USE_PPTR
#endif /* _USE_FULL_PATH != 0xfeed */
#ifdef MULTIPROCESSOR
/*
* Make the running processor's pda address available in k0.
* Note that k1 is lost in addition to k0 for MP.
*
* Some of the things buried in this macro:
* -pda_t is 512 bytes
* -ss_to_vid is an array of bytes
* -EV_GET_SPNUM returns a "physical cpuid", a
* number suitable for use as an index into ss_to_vid.
*
* For IP21, the slices are numbered 0 and 2 in the SPNUM register,
* but software referes to them as slices 0 and 1 to avoid confusing
* users. This means we have to do a little extra work with the
* contents of the SPNUM register.
*/
#ifdef EVEREST
#if IP21
#define _get_gpda(dst,scratch) \
LI scratch,EV_SPNUM; \
ld scratch,0(scratch); \
and scratch,EV_SPNUM_MASK; \
and dst,scratch,EV_PROCNUM_MASK; \
srl dst,EV_PROCNUM_SHFT; \
srl scratch,EV_SLOTNUM_SHFT; \
sll scratch,EV_SLOTNUM_SHFT; \
or scratch,dst; \
sll scratch,1; /* ss_to_vid is array of cpuid_t (now a short) */ \
LA dst,ss_to_vid; \
PTR_ADDU dst,scratch; \
lh scratch,0(dst); \
sll scratch,GENERIC_PDASIZE_2; \
LA dst,gen_pda_tab; \
PTR_ADDU dst,scratch
#endif /* IP21 */
#if IP19 || IP25
#define _get_gpda(dst,scratch) \
LI scratch,EV_SPNUM; \
ld scratch,0(scratch); \
LA dst,ss_to_vid; \
and scratch,EV_SPNUM_MASK; \
sll scratch,1; /* ss_to_vid is array of cpuid_t (now a short) */ \
PTR_ADDU dst,scratch; \
lh scratch,0(dst); \
sll scratch,GENERIC_PDASIZE_2; \
LA dst,gen_pda_tab; \
PTR_ADDU dst,scratch
#endif /* IP19 || IP25 */
#elif IP27
#define GPDA_IALIAS_BASE 0x9200000001000000
#define PI_CPU_NUM 0x000020
#define NI_STATUS_REV_ID 0x600000
#define NI_NODEID_SHFT 8
#define NI_NODEID_MASK 0x1ff
#define _get_my_vid(dst,scratch) \
LI scratch,GPDA_IALIAS_BASE+NI_STATUS_REV_ID; \
ld dst,(scratch) ;\
dsrl dst,NI_NODEID_SHFT ;\
and dst,NI_NODEID_MASK ;\
sll dst, 1;\
LI scratch,GPDA_IALIAS_BASE+PI_CPU_NUM ;\
ld scratch,(scratch) ;\
PTR_ADDU dst,scratch; \
sll dst, 1;\
LA scratch, nasid_slice_to_vid;\
PTR_ADDU dst, scratch; \
lh dst, 0(dst)
#define _get_gpda(dst,scratch) \
_get_my_vid(dst, scratch) ;\
sll dst,PTR_SCALESHIFT ;\
LA scratch,gen_pda_tabp ;\
PTR_ADDU dst,scratch ;\
ld dst, 0(dst)
#elif IP30
#define _get_gpda(dst,scratch) \
CLI scratch,PHYS_TO_COMPATK1(HEART_PRID); \
ld scratch,0(scratch); \
li dst,GENERIC_PDASIZE_2; \
sllv scratch,scratch,dst; \
LA dst,gen_pda_tab; \
PTR_ADDU dst,scratch
#else
#error genpda.h _get_gpda -- unknown MP CPU!
#endif
#else /* Non MULTIPROCESSOR Platforms */
#define _get_gpda(dst,scratch) \
LA dst,gen_pda_tab
#endif /* MULTIPROCESSOR */
#ifdef _LANGUAGE_ASSEMBLY
/*
* Offsets into Generic PDA. Must match C structure above.
*/
#define GPDA_MAGIC_OFF 0
#define GPDA_EPC_SV GPDA_MAGIC_OFF + R_SIZE
#define GPDA_AT_SV GPDA_EPC_SV + R_SIZE
#define GPDA_V0_SV GPDA_AT_SV + R_SIZE
#define GPDA_BADVADDR_SV GPDA_V0_SV + R_SIZE
#define GPDA_CAUSE_SV GPDA_BADVADDR_SV + R_SIZE
#define GPDA_SP_SV GPDA_CAUSE_SV + R_SIZE
#define GPDA_SR_SV GPDA_SP_SV + R_SIZE
#define GPDA_EXC_SV GPDA_SR_SV + R_SIZE
#define GPDA_STACK_MODE GPDA_EXC_SV + R_SIZE
#define GPDA_MODE_SV GPDA_STACK_MODE + R_SIZE
#define GPDA_MY_VIRTID GPDA_MODE_SV + R_SIZE
#define GPDA_MY_PHYSID GPDA_MY_VIRTID + R_SIZE
#define GPDA_NOTFIRST GPDA_MY_PHYSID + R_SIZE
#define GPDA_FIRST_EPC GPDA_NOTFIRST + R_SIZE
#define GPDA_RTN_ADDR_SV GPDA_FIRST_EPC + R_SIZE
#define GPDA_INITIAL_SP GPDA_RTN_ADDR_SV + R_SIZE
#define GPDA_FAULT_SP GPDA_INITIAL_SP + P_SIZE
#define GPDA_REGS GPDA_FAULT_SP + P_SIZE
#define GPDA_NOFAULT GPDA_REGS + P_SIZE
#define GPDA_CACHE_ERR_SV GPDA_NOFAULT + P_SIZE
#define GPDA_ERROR_EPC_SV GPDA_CACHE_ERR_SV+ R_SIZE
/* Symmon-specific entries */
#define GPDA_SV_GP GPDA_ERROR_EPC_SV + R_SIZE
#define GPDA_SV_RA GPDA_SV_GP + K_MACHREG_SIZE
#define GPDA_SV_K1 GPDA_SV_RA + K_MACHREG_SIZE
#define GPDA_SYMMON_SV_AT GPDA_SV_K1 + K_MACHREG_SIZE
#define GPDA_DBG_STACK GPDA_SYMMON_SV_AT + K_MACHREG_SIZE
#define GPDA_EXC_STACK GPDA_DBG_STACK + P_SIZE
#define GPDA_DBG_MODE GPDA_EXC_STACK + P_SIZE
#define GPDA_DBG_MODESAV GPDA_DBG_MODE + (_MIPS_SZINT/8)
#define GPDA_DBG_EXC GPDA_DBG_MODESAV + (_MIPS_SZINT/8)
#endif /* _LANGUAGE_ASSEMBLY */
#endif /* __GENPDA_H__ */