/* TRACE.C (c) Copyright Jan Jaeger, 2000-2006 */ /* Implicit tracing functions */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2006 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2006 */ /*-------------------------------------------------------------------*/ /* This module contains procedures for creating entries in the */ /* system trace table as described in the manuals: */ /* SA22-7201 ESA/390 Principles of Operation */ /* SA22-7832 z/Architecture Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* ASN-and-LX-reuse facility - Roger Bowler July 2004*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_TRACE_C_) #define _TRACE_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_TRACING) #if !defined(_TRACE_H) #define _TRACE_H /*-------------------------------------------------------------------*/ /* Format definitions for trace table entries */ /*-------------------------------------------------------------------*/ typedef struct _TRACE_F1_BR { FWORD newia24; /* Bits 0-7 are zeros */ } TRACE_F1_BR; typedef struct _TRACE_F2_BR { FWORD newia31; /* Bit 0 is one */ } TRACE_F2_BR; typedef struct _TRACE_F3_BR { BYTE format; /* B'01010010' */ #define TRACE_F3_BR_FMT 0x52 BYTE fmt2; /* B'1100' B'0000' */ #define TRACE_F3_BR_FM2 0xC0 HWORD resv; DBLWRD newia64; } TRACE_F3_BR; typedef struct _TRACE_F1_BSG { BYTE format; /* B'01000001' */ #define TRACE_F1_BSG_FMT 0x41 BYTE alet[3]; FWORD newia; } TRACE_F1_BSG; typedef struct _TRACE_F2_BSG { BYTE format; /* B'01000010' */ #define TRACE_F2_BSG_FMT 0x42 BYTE alet[3]; DBLWRD newia; } TRACE_F2_BSG; typedef struct _TRACE_F1_MS { BYTE format; #define TRACE_F1_MS_FMT 0x51 BYTE fmt2; #define TRACE_F1_MS_FM2 0x30 HWORD resv; FWORD newia; } TRACE_F1_MS; typedef struct _TRACE_F2_MS { BYTE format; #define TRACE_F2_MS_FMT 0x51 BYTE fmt2; #define TRACE_F2_MS_FM2 0x20 HWORD resv; FWORD newia; } TRACE_F2_MS; typedef struct _TRACE_F3_MS { BYTE format; #define TRACE_F3_MS_FMT 0x52 BYTE fmt2; #define TRACE_F3_MS_FM2 0x60 HWORD resv; DBLWRD newia; } TRACE_F3_MS; typedef struct _TRACE_F1_MSB { BYTE format; #define TRACE_F1_MSB_FMT 0x51 BYTE fmt2; #define TRACE_F1_MSB_FM2 0xA0 HWORD resv; FWORD newia; } TRACE_F1_MSB; typedef struct _TRACE_F2_MSB { BYTE format; #define TRACE_F2_MSB_FMT 0x51 BYTE fmt2; #define TRACE_F2_MSB_FM2 0xB0 HWORD resv; FWORD newia; } TRACE_F2_MSB; typedef struct _TRACE_F3_MSB { BYTE format; #define TRACE_F3_MSB_FMT 0x52 BYTE fmt2; #define TRACE_F3_MSB_FM2 0xF0 HWORD resv; DBLWRD newia; } TRACE_F3_MSB; typedef struct _TRACE_F1_PT { BYTE format; #define TRACE_F1_PT_FMT 0x31 BYTE pswkey; #define TRACE_F1_PT_FM2 0x00 HWORD newpasn; FWORD r2; } TRACE_F1_PT; typedef struct _TRACE_F2_PT { BYTE format; #define TRACE_F2_PT_FMT 0x31 BYTE pswkey; #define TRACE_F2_PT_FM2 0x08 HWORD newpasn; FWORD r2; } TRACE_F2_PT; typedef struct _TRACE_F3_PT { BYTE format; #define TRACE_F3_PT_FMT 0x32 BYTE pswkey; #define TRACE_F3_PT_FM2 0x0C HWORD newpasn; DBLWRD r2; } TRACE_F3_PT; typedef struct _TRACE_F1_SSAR { BYTE format; #define TRACE_F1_SSAR_FMT 0x10 BYTE extfmt; HWORD newsasn; } TRACE_F1_SSAR; typedef struct _TRACE_F1_TRACE { BYTE format; BYTE zero; HWORD tod1631; FWORD tod3263; FWORD operand; FWORD regs[16]; } TRACE_F1_TRACE; typedef struct _TRACE_F2_TRACE { BYTE format; BYTE extfmt; HWORD tod1631; DBLWRD tod3279; FWORD operand; DBLWRD regs[16]; } TRACE_F2_TRACE; typedef struct _TRACE_F1_PR { BYTE format; #define TRACE_F1_PR_FMT 0x32 BYTE pswkey; #define TRACE_F1_PR_FM2 0x00 HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F1_PR; typedef struct _TRACE_F2_PR { BYTE format; #define TRACE_F2_PR_FMT 0x32 BYTE pswkey; #define TRACE_F2_PR_FM2 0x00 HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F2_PR; typedef struct _TRACE_F3_PR { BYTE format; #define TRACE_F3_PR_FMT 0x33 BYTE pswkey; #define TRACE_F3_PR_FM2 0x03 HWORD newpasn; FWORD retna; DBLWRD newia; } TRACE_F3_PR; typedef struct _TRACE_F4_PR { BYTE format; #define TRACE_F4_PR_FMT 0x32 BYTE pswkey; #define TRACE_F4_PR_FM2 0x08 HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F4_PR; typedef struct _TRACE_F5_PR { BYTE format; #define TRACE_F5_PR_FMT 0x32 BYTE pswkey; #define TRACE_F5_PR_FM2 0x0A HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F5_PR; typedef struct _TRACE_F6_PR { BYTE format; #define TRACE_F6_PR_FMT 0x33 BYTE pswkey; #define TRACE_F6_PR_FM2 0x0B HWORD newpasn; FWORD retna; DBLWRD newia; } TRACE_F6_PR; typedef struct _TRACE_F7_PR { BYTE format; #define TRACE_F7_PR_FMT 0x33 BYTE pswkey; #define TRACE_F7_PR_FM2 0x0C HWORD newpasn; DBLWRD retna; FWORD newia; } TRACE_F7_PR; typedef struct _TRACE_F8_PR { BYTE format; #define TRACE_F8_PR_FMT 0x33 BYTE pswkey; #define TRACE_F8_PR_FM2 0x0E HWORD newpasn; DBLWRD retna; FWORD newia; } TRACE_F8_PR; typedef struct _TRACE_F9_PR { BYTE format; #define TRACE_F9_PR_FMT 0x34 BYTE pswkey; #define TRACE_F9_PR_FM2 0x0F HWORD newpasn; DBLWRD retna; FWORD newia; } TRACE_F9_PR; typedef struct _TRACE_F1_PC { BYTE format; #define TRACE_F1_PC_FMT 0x21 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; FWORD retna; } TRACE_F1_PC; typedef struct _TRACE_F2_PC { BYTE format; #define TRACE_F2_PC_FMT 0x22 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; DBLWRD retna; } TRACE_F2_PC; typedef struct _TRACE_F3_PC { BYTE format; #define TRACE_F3_PC_FMT 0x21 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; FWORD retna; } TRACE_F3_PC; typedef struct _TRACE_F4_PC { BYTE format; #define TRACE_F4_PC_FMT 0x22 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; DBLWRD retna; } TRACE_F4_PC; typedef struct _TRACE_F5_PC { BYTE format; #define TRACE_F5_PC_FMT 0x22 BYTE pswkey; #define TRACE_F5_PC_FM2 0x08 HWORD resv; FWORD retna; FWORD pcnum; } TRACE_F5_PC; typedef struct _TRACE_F6_PC { BYTE format; #define TRACE_F6_PC_FMT 0x22 BYTE pswkey; #define TRACE_F6_PC_FM2 0x0A HWORD resv; FWORD retna; FWORD pcnum; } TRACE_F6_PC; typedef struct _TRACE_F7_PC { BYTE format; #define TRACE_F7_PC_FMT 0x23 BYTE pswkey; #define TRACE_F7_PC_FM2 0x0E HWORD resv; DBLWRD retna; FWORD pcnum; } TRACE_F7_PC; typedef struct _TRACE_F1_TR { BYTE format; #define TRACE_F1_TR_FMT 0x70 BYTE fmt2; #define TRACE_F1_TR_FM2 0x00 HWORD clk16; FWORD clk32; FWORD operand; FWORD reg[16]; } TRACE_F1_TR; typedef struct _TRACE_F2_TR { BYTE format; #define TRACE_F2_TR_FMT 0x70 BYTE fmt2; #define TRACE_F2_TR_FM2 0x80 HWORD clk0; FWORD clk16; FWORD clk48; FWORD operand; DBLWRD reg[16]; } TRACE_F2_TR; #endif /*!defined(_TRACE_H)*/ /*-------------------------------------------------------------------*/ /* Reserve space for a new trace entry */ /* */ /* Input: */ /* size Number of bytes required for trace entry */ /* regs Pointer to the CPU register context */ /* Output: */ /* abs_guest Guest absolute address of trace entry (if SIE) */ /* Return value: */ /* Absolute address of new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ static inline RADR ARCH_DEP(get_trace_entry) (RADR *abs_guest, int size, REGS *regs) { RADR n; /* Addr of trace table entry */ /* Obtain the trace entry address from control register 12 */ n = regs->CR(12) & CR12_TRACEEA; /* Apply low-address protection to trace entry address */ if (ARCH_DEP(is_low_address_protected) (n, regs)) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = (n & STORAGE_KEY_PAGEMASK); regs->excarid = 0; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION); } /* Program check if trace entry is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Program check if storing would overflow a 4K page boundary */ if ( ((n + size) & PAGEFRAME_PAGEMASK) != (n & PAGEFRAME_PAGEMASK) ) ARCH_DEP(program_interrupt) (regs, PGM_TRACE_TABLE_EXCEPTION); /* Convert trace entry real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); #if defined(_FEATURE_SIE) *abs_guest = n; SIE_TRANSLATE(&n, ACCTYPE_WRITE, regs); #endif /*defined(_FEATURE_SIE)*/ return n; } /* end function ARCH_DEP(get_trace_entry) */ /*-------------------------------------------------------------------*/ /* Commit a new trace entry */ /* */ /* Input: */ /* abs_guest Guest absolute address of trace entry (if SIE) */ /* raddr Absolute address of trace entry */ /* size Number of bytes reserved for trace entry */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after committing the trace entry */ /*-------------------------------------------------------------------*/ static inline CREG ARCH_DEP(set_trace_entry) (RADR abs_guest, RADR raddr, int size, REGS *regs) { #if defined(_FEATURE_SIE) RADR abs_host; abs_host = raddr; #endif /*defined(_FEATURE_SIE)*/ raddr += size; #if defined(_FEATURE_SIE) /* Recalculate the Guest absolute address */ raddr = abs_guest + (raddr - abs_host); #endif /*defined(_FEATURE_SIE)*/ /* Convert trace entry absolute address back to real address */ raddr = APPLY_PREFIXING (raddr, regs->PX); /* Return updated value of control register 12 */ return (regs->CR(12) & ~CR12_TRACEEA) | raddr; } /* end function ARCH_DEP(set_trace_entry) */ /*-------------------------------------------------------------------*/ /* Form implicit branch trace entry */ /* */ /* Input: */ /* amode Non-zero if branch destination is a 31-bit address */ /* or a 64 bit address */ /* ia Branch destination address */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_br) (int amode, VADR ia, REGS *regs) { RADR raddr; RADR ag; int size; #if defined(FEATURE_ESAME) if(amode && ia > 0xFFFFFFFFULL) { TRACE_F3_BR *tte; size = sizeof(TRACE_F3_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_BR_FMT; tte->fmt2 = TRACE_F3_BR_FM2; STORE_HW(tte->resv,0); STORE_DW(tte->newia64,ia); } else #endif /*defined(FEATURE_ESAME)*/ if(amode) { TRACE_F2_BR *tte; size = sizeof(TRACE_F2_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); STORE_FW(tte->newia31,ia | 0x80000000); } else { TRACE_F1_BR *tte; size = sizeof(TRACE_F1_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); STORE_FW(tte->newia24,ia & 0x00FFFFFF); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_br) */ #if defined(FEATURE_SUBSPACE_GROUP) /*-------------------------------------------------------------------*/ /* Form implicit BSG trace entry */ /* */ /* Input: */ /* alet Destination address space ALET */ /* ia Branch destination address */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_bsg) (U32 alet, VADR ia, REGS *regs) { RADR raddr; RADR ag; int size; #if defined(FEATURE_ESAME) if(regs->psw.amode64) { TRACE_F2_BSG *tte; size = sizeof(TRACE_F2_BSG); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_BSG_FMT; tte->alet[0] = (alet >> 16) & 0xFF; tte->alet[1] = (alet >> 8) & 0xFF; tte->alet[2] = alet & 0xFF; STORE_DW(tte->newia,ia); } else #endif /*defined(FEATURE_ESAME)*/ { TRACE_F1_BSG *tte; size = sizeof(TRACE_F1_BSG); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_BSG_FMT; tte->alet[0] = ((alet >> 17) & 0x80) | ((alet >> 16) & 0x7F); tte->alet[1] = (alet >> 8) & 0xFF; tte->alet[2] = alet & 0xFF; if ((ia & 0x80000000) == 0) ia &=0x00FFFFFF; STORE_FW(tte->newia,ia); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_bsg) */ #endif /*defined(FEATURE_SUBSPACE_GROUP)*/ /*-------------------------------------------------------------------*/ /* Form implicit SSAR/SSAIR trace entry */ /* */ /* Input: */ /* ssair 1=SSAIR instruction, 0=SSAR instruction */ /* sasn Secondary address space number */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_ssar) (int ssair, U16 sasn, REGS *regs) { RADR raddr; RADR ag; int size; BYTE nbit = (ssair ? 1 : 0); { TRACE_F1_SSAR *tte; size = sizeof(TRACE_F1_SSAR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_SSAR_FMT; tte->extfmt = 0 | nbit; STORE_HW(tte->newsasn,sasn); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_ssar) */ /*-------------------------------------------------------------------*/ /* Form implicit PC trace entry */ /* */ /* Input: */ /* pcea PC instruction effective address (20 or 32 bits) */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_pc) (U32 pcea, REGS *regs) { RADR raddr; RADR ag; int size; int eamode; regs->psw.IA &= ADDRESS_MAXWRAP(regs); eamode = regs->psw.amode64; #if defined(FEATURE_ESAME) if (ASN_AND_LX_REUSE_ENABLED(regs)) { if ((pcea & PC_BIT44) && regs->psw.amode64 && regs->psw.IA_H) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled, 32-bit PC number is used, and bits 0-31 of return address are not all zeros */ TRACE_F7_PC *tte; size = sizeof(TRACE_F7_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F7_PC_FMT; tte->pswkey = regs->psw.pkey | TRACE_F7_PC_FM2 | eamode; STORE_HW(tte->resv, 0x0000); STORE_DW(tte->retna, regs->psw.IA_G | PROBSTATE(®s->psw)); STORE_FW(tte->pcnum, pcea); } else if ((pcea & PC_BIT44) && regs->psw.amode64) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled, 32-bit PC number is used, and bits 0-31 of return address are all zeros */ TRACE_F6_PC *tte; size = sizeof(TRACE_F6_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F6_PC_FMT; tte->pswkey = regs->psw.pkey | TRACE_F6_PC_FM2 | eamode; STORE_HW(tte->resv, 0x0000); STORE_FW(tte->retna, regs->psw.IA_L | PROBSTATE(®s->psw)); STORE_FW(tte->pcnum, pcea); } else if ((pcea & PC_BIT44)) { /* In 24-bit or 31-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled and 32-bit PC number is used */ TRACE_F5_PC *tte; size = sizeof(TRACE_F5_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F5_PC_FMT; tte->pswkey = regs->psw.pkey | TRACE_F5_PC_FM2 | eamode; STORE_HW(tte->resv, 0x0000); STORE_FW(tte->retna, (regs->psw.amode << 31) | regs->psw.IA_L | PROBSTATE(®s->psw)); STORE_FW(tte->pcnum, pcea); } else if(regs->psw.amode64) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled and 20-bit PC number is used */ TRACE_F4_PC *tte; size = sizeof(TRACE_F4_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F4_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_DW(tte->retna, regs->psw.IA_G | PROBSTATE(®s->psw)); } else { /* In 24-bit or 31-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled and 20-bit PC number is used */ TRACE_F3_PC *tte; size = sizeof(TRACE_F3_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_FW(tte->retna, (regs->psw.amode << 31) | regs->psw.IA_L | PROBSTATE(®s->psw)); } } /* end ASN_AND_LX_REUSE_ENABLED */ else if(regs->psw.amode64) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is not enabled */ TRACE_F2_PC *tte; size = sizeof(TRACE_F2_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_DW(tte->retna, regs->psw.IA_G | PROBSTATE(®s->psw)); } else #endif /*defined(FEATURE_ESAME)*/ { /* In 24-bit or 31-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is not enabled */ TRACE_F1_PC *tte; size = sizeof(TRACE_F1_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_FW(tte->retna, (regs->psw.amode << 31) | regs->psw.IA_L | PROBSTATE(®s->psw)); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_pc) */ #if defined(_MSVC_) /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */ #pragma optimize("",off) #endif /*defined(_MSVC_)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* Form implicit PR trace entry */ /* */ /* Input: */ /* newregs Pointer to registers after PR instruction */ /* regs Pointer to registers before PR instruction */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_pr) (REGS *newregs, REGS *regs) { RADR raddr; RADR ag; int size; regs->psw.IA &= ADDRESS_MAXWRAP(regs); #if defined(FEATURE_ESAME) if(!regs->psw.amode64 && !newregs->psw.amode64) #endif /*defined(FEATURE_ESAME)*/ { TRACE_F1_PR *tte; size = sizeof(TRACE_F1_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F1_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, (newregs->psw.amode << 31) | newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, (regs->psw.amode << 31) | regs->psw.IA_L); } #if defined(FEATURE_ESAME) else if(regs->psw.amode64 && regs->psw.IA_H == 0 && !newregs->psw.amode64) { TRACE_F2_PR *tte; size = sizeof(TRACE_F2_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F2_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, (newregs->psw.amode << 31) | newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, (regs->psw.amode << 31) | regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H != 0 && !newregs->psw.amode64) { TRACE_F3_PR *tte; size = sizeof(TRACE_F3_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F3_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, (newregs->psw.amode << 31) | newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_DW(tte->newia, regs->psw.IA_G); } else if(!regs->psw.amode64 && newregs->psw.amode64 && newregs->psw.IA_H == 0) { TRACE_F4_PR *tte; size = sizeof(TRACE_F4_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F4_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F4_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, (regs->psw.amode << 31) | regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H == 0 && newregs->psw.amode64 && newregs->psw.IA_H == 0) { TRACE_F5_PR *tte; size = sizeof(TRACE_F5_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F5_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F5_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H != 0 && newregs->psw.amode64 && newregs->psw.IA_H == 0) { TRACE_F6_PR *tte; size = sizeof(TRACE_F6_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F6_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F6_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_DW(tte->newia, regs->psw.IA_G); } else if(!regs->psw.amode64 && newregs->psw.amode64 && newregs->psw.IA_H != 0) { TRACE_F7_PR *tte; size = sizeof(TRACE_F7_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F7_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F7_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_DW(tte->retna, newregs->psw.IA_G | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, (regs->psw.amode << 31) | regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H == 0 && newregs->psw.amode64 && newregs->psw.IA_H != 0) { TRACE_F8_PR *tte; size = sizeof(TRACE_F8_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F8_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F8_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_DW(tte->retna, newregs->psw.IA_G | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, regs->psw.IA_L); } else /* if(regs->psw.amode64 && regs->psw.IA_H != 0 && newregs->psw.amode64 && newregs->psw.IA_H != 0) */ { TRACE_F9_PR *tte; size = sizeof(TRACE_F9_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F9_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F9_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_DW(tte->retna, newregs->psw.IA_G | PROBSTATE(&newregs->psw)); STORE_DW(tte->newia, regs->psw.IA_G); } #endif /*defined(FEATURE_ESAME)*/ return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_pr) */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(_MSVC_) /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */ #pragma optimize("",on) #endif /*defined(_MSVC_)*/ /*-------------------------------------------------------------------*/ /* Form implicit PT/PTI trace entry */ /* */ /* Input: */ /* pti 1=PTI instruction, 0=PT instruction */ /* pasn Primary address space number */ /* gpr2 Contents of PT second operand register */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_pt) (int pti, U16 pasn, GREG gpr2, REGS *regs) { RADR raddr; RADR ag; int size; BYTE nbit = (pti ? 1 : 0); #if defined(FEATURE_ESAME) if(regs->psw.amode64 && gpr2 > 0xFFFFFFFFULL) { TRACE_F3_PT *tte; size = sizeof(TRACE_F3_PT); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_PT_FMT; tte->pswkey = regs->psw.pkey | TRACE_F3_PT_FM2 | nbit; STORE_HW(tte->newpasn, pasn); STORE_DW(tte->r2, gpr2); } else if(regs->psw.amode64) { TRACE_F2_PT *tte; size = sizeof(TRACE_F2_PT); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_PT_FMT; tte->pswkey = regs->psw.pkey | TRACE_F2_PT_FM2 | nbit; STORE_HW(tte->newpasn, pasn); STORE_FW(tte->r2, gpr2 & 0xFFFFFFFF); } else #endif /*defined(FEATURE_ESAME)*/ { TRACE_F1_PT *tte; size = sizeof(TRACE_F1_PT); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_PT_FMT; tte->pswkey = regs->psw.pkey | TRACE_F1_PT_FM2 | nbit; STORE_HW(tte->newpasn, pasn); STORE_FW(tte->r2, gpr2 & 0xFFFFFFFF); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_pt) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* Form implicit MS trace entry */ /* */ /* Input: */ /* br Mode switch branch indicator */ /* ia updated instruction address */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_ms) (int br, VADR ia, REGS *regs) { RADR raddr; RADR ag; int size; regs->psw.IA &= ADDRESS_MAXWRAP(regs); if(!br) { if(!regs->psw.amode64) { TRACE_F1_MS *tte; size = sizeof(TRACE_F1_MS); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_MS_FMT; tte->fmt2 = TRACE_F1_MS_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, regs->psw.IA | (regs->psw.amode << 31)); } else if(regs->psw.amode64 && ia <= 0x7FFFFFFF) { TRACE_F2_MS *tte; size = sizeof(TRACE_F2_MS); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_MS_FMT; tte->fmt2 = TRACE_F2_MS_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, regs->psw.IA); } else { TRACE_F3_MS *tte; size = sizeof(TRACE_F3_MS); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_MS_FMT; tte->fmt2 = TRACE_F3_MS_FM2; STORE_HW(tte->resv, 0); STORE_DW(tte->newia, regs->psw.IA); } } else { if(!regs->psw.amode64) { TRACE_F1_MSB *tte; size = sizeof(TRACE_F1_MSB); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_MSB_FMT; tte->fmt2 = TRACE_F1_MSB_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, ia); } else if(regs->psw.amode64 && ia <= 0x7FFFFFFF) { TRACE_F2_MSB *tte; size = sizeof(TRACE_F2_MSB); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_MSB_FMT; tte->fmt2 = TRACE_F2_MSB_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, ia); } else { TRACE_F3_MSB *tte; size = sizeof(TRACE_F3_MSB); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_MSB_FMT; tte->fmt2 = TRACE_F3_MSB_FM2; STORE_HW(tte->resv, 0); STORE_DW(tte->newia, ia); } } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_ms) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* Form explicit TRACE trace entry */ /* */ /* Input: */ /* r1, r3 registers identifying register space to be written */ /* op Trace operand */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_tr) (int r1, int r3, U32 op, REGS *regs) { RADR raddr; RADR ag; int size; int i, j, n; U64 dreg; { TRACE_F1_TR *tte; size = sizeof(TRACE_F1_TR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); /* Calculate the number of registers to be traced, minus 1 */ n = ( r3 < r1 ) ? r3 + 16 - r1 : r3 - r1; /* Retrieve the TOD clock value and shift out the epoch */ dreg = (tod_clock(regs) << 8) | regs->cpuad; tte->format = TRACE_F1_TR_FMT | n; tte->fmt2 = TRACE_F1_TR_FM2; STORE_HW(tte->clk16, (dreg >> 32) & 0xFFFF); STORE_FW(tte->clk32, dreg & 0xFFFFFFFF); STORE_FW(tte->operand, op); for(i = r1, j = 0; ; ) { STORE_FW(tte->reg[j++], regs->GR_L(i)); /* Regdump is complete when r3 is done */ if(r3 == i) break; /* Update register number and wrap */ i++; i &= 15; } } return ARCH_DEP(set_trace_entry) (ag, raddr, size - (4 * (15 - n)), regs); } /* end function ARCH_DEP(trace_tr) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* Form explicit TRACG trace entry */ /* */ /* Input: */ /* r1, r3 registers identifying register space to be written */ /* op Trace operand */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_tg) (int r1, int r3, U32 op, REGS *regs) { RADR raddr; RADR ag; int size; int i, j, n; U64 dreg; { TRACE_F2_TR *tte; size = sizeof(TRACE_F2_TR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); /* Calculate the number of registers to be traced, minus 1 */ n = ( r3 < r1 ) ? r3 + 16 - r1 : r3 - r1; /* Retrieve the TOD clock value including the epoch */ dreg = tod_clock(regs); tte->format = TRACE_F2_TR_FMT | n; tte->fmt2 = TRACE_F2_TR_FM2; STORE_HW(tte->clk0, (dreg >> 48) & 0xFFFF); /* shift out the epoch */ dreg = (dreg << 8) | regs->cpuad; STORE_FW(tte->clk16, (dreg >> 32) & 0xFFFFFFFF); STORE_FW(tte->clk48, dreg & 0xFFFFFFFF); STORE_FW(tte->operand, op); for(i = r1, j = 0; ; ) { STORE_DW(tte->reg[j++], regs->GR_G(i)); /* Regdump is complete when r3 is done */ if(r3 == i) break; /* Update register number and wrap */ i++; i &= 15; } } return ARCH_DEP(set_trace_entry) (ag, raddr, size - (8 * (15 - n)), regs); } /* end function ARCH_DEP(trace_tg) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_TRACING)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "trace.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "trace.c" #endif #endif /*!defined(_GEN_ARCH)*/