/* CONTROL.C (c) Copyright Roger Bowler, 1994-2002 */ /* ESA/390 CPU Emulator */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2002 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2002 */ /*-------------------------------------------------------------------*/ /* This module implements all control instructions of the */ /* S/370 and ESA/390 architectures, as described in the manuals */ /* GA22-7000-03 System/370 Principles of Operation */ /* SA22-7201-06 ESA/390 Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Bad frame support by Jan Jaeger */ /* Branch tracing by Jan Jaeger */ /* CSP instructions by Jan Jaeger */ /* Instruction decode by macros - Jan Jaeger */ /* Prevent TOD from going backwards in time - Jan Jaeger */ /* Instruction decode rework - Jan Jaeger */ /* PR may lose pending interrupts - Jan Jaeger */ /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */ /* ESAME low-address protection - Roger Bowler */ /* ESAME linkage stack operations - Roger Bowler */ /* ESAME BSA instruction - Roger Bowler v209c*/ /*-------------------------------------------------------------------*/ #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(OPTION_FISHIO) #include "w32chan.h" #endif // defined(OPTION_FISHIO) #if defined(FEATURE_BRANCH_AND_SET_AUTHORITY) /*-------------------------------------------------------------------*/ /* B25A BSA - Branch and Set Authority [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_set_authority) { int r1, r2; /* Values of R fields */ U32 ducto; /* DUCT origin */ U32 duct_pkrp; /* DUCT PKM/Key/RA/P word */ RADR duct_reta; /* DUCT return address/amode */ BYTE key; /* New PSW key */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ RRE(inst, execflag, regs, r1, r2); /* Special operation exception if ASF is not enabled */ if (!ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_BSA)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Load real address of dispatchable unit control table */ ducto = regs->CR(2) & CR2_DUCTO; /* Apply low-address protection to stores into the DUCT */ if (ARCH_DEP(is_low_address_protected) (ducto, 0, regs)) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = (ducto & STORAGE_KEY_PAGEMASK); regs->excarid = 0; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION); } /* Convert DUCT real address to absolute address */ ducto = APPLY_PREFIXING (ducto, regs->PX); /* Program check if DUCT origin address is invalid */ if (ducto >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(FEATURE_ESAME) /* For ESAME, load the PKM/Key/RA/P from DUCT word 5, and load the return address and amode from DUCT words 8 and 9 (note: the DUCT cannot cross a page boundary) */ duct_pkrp = ARCH_DEP(fetch_fullword_absolute) (ducto+20, regs); duct_reta = ARCH_DEP(fetch_doubleword_absolute) (ducto+32, regs); #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390, load the PKM/Key/RA/P from DUCT word 9, and load the return address and amode from DUCT word 8 (note: the DUCT cannot cross a page boundary) */ duct_pkrp = ARCH_DEP(fetch_fullword_absolute) (ducto+36, regs); duct_reta = ARCH_DEP(fetch_fullword_absolute) (ducto+32, regs); #endif /*!defined(FEATURE_ESAME)*/ /* Perform base authority or reduced authority operation */ if ((duct_pkrp & DUCT_RA) == 0) { /* In base authority state R2 cannot specify register zero */ if (r2 == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #ifdef FEATURE_TRACING /* Perform tracing */ if (regs->CR(12) & CR12_BRTRACE) newcr12 = ARCH_DEP(trace_br) (regs->GR_L(r2) & 0x80000000, regs->GR_L(r2), regs); #endif /*FEATURE_TRACING*/ /* Obtain the new PSW key from R1 register bits 24-27 */ key = regs->GR_L(r1) & 0x000000F0; /* Privileged operation exception if in problem state and current PSW key mask does not permit new key value */ if (regs->psw.prob && ((regs->CR(3) << (key >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Save current PSW amode and instruction address */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { duct_reta = regs->psw.IA; } else #endif /*!defined(FEATURE_ESAME)*/ { duct_reta = regs->psw.IA & DUCT_IA31; if (regs->psw.amode) duct_reta |= DUCT_AM31; } /* Save current PSW key mask, PSW key, and problem state */ duct_pkrp = (regs->CR(3) & CR3_KEYMASK) | regs->psw.pkey; if (regs->psw.prob) duct_pkrp |= DUCT_PROB; /* Set the reduced authority bit */ duct_pkrp |= DUCT_RA; #if defined(FEATURE_ESAME) /* For ESAME, store the PKM/Key/RA/P into DUCT word 5, and store the return address and amode into DUCT words 8 and 9 (note: the DUCT cannot cross a page boundary) */ ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+20, regs); ARCH_DEP(store_doubleword_absolute) (duct_reta, ducto+32, regs); #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390, store the PKM/Key/RA/P into DUCT word 9, and store the return address and amode into DUCT word 8 (note: the DUCT cannot cross a page boundary) */ ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+36, regs); ARCH_DEP(store_fullword_absolute) (duct_reta, ducto+32, regs); #endif /*!defined(FEATURE_ESAME)*/ /* Load new PSW key and PSW key mask from R1 register */ regs->psw.pkey = key; regs->CR_LHH(3) &= regs->GR_LHH(r1); /* Set the problem state bit in the current PSW */ regs->psw.prob = 1; /* Set PSW instruction address and amode from R2 register */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { regs->psw.IA = regs->GR_G(r2); } else #endif /*defined(FEATURE_ESAME)*/ if (regs->GR_L(r2) & 0x80000000) { #if defined(FEATURE_ESAME) regs->psw.amode64 = 0; #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode = 1; regs->psw.AMASK = AMASK31; regs->psw.IA = regs->GR_L(r2) & AMASK31; } else { #if defined(FEATURE_ESAME) regs->psw.amode64 = #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode = 0; regs->psw.AMASK = AMASK24; regs->psw.IA = regs->GR_L(r2) & AMASK24; } } /* end if(BSA-ba) */ else { /* BSA-ra */ /* In reduced authority state R2 must specify register zero */ if (r2 != 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #ifdef FEATURE_TRACING /* Perform tracing */ if (regs->CR(12) & CR12_BRTRACE) newcr12 = ARCH_DEP(trace_br) (duct_reta & DUCT_AM31, duct_reta &DUCT_IA31, regs); #endif /*FEATURE_TRACING*/ /* If R1 is non-zero, save the current PSW addressing mode and instruction address in the R1 register */ if (r1 != 0) { #if defined(FEATURE_ESAME) if (regs->psw.amode64) { regs->GR_G(r1) = regs->psw.IA; } else #endif /*defined(FEATURE_ESAME)*/ { regs->GR_L(r1) = regs->psw.IA; if (regs->psw.amode) regs->GR_L(r1) |= 0x80000000; } } /* Restore PSW amode and instruction address from the DUCT */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { regs->psw.IA = duct_reta; } else #endif /*defined(FEATURE_ESAME)*/ { regs->psw.IA = duct_reta & DUCT_IA31; regs->psw.amode = (duct_reta & DUCT_AM31) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; } /* Restore the PSW key mask from the DUCT */ regs->CR(3) &= 0x0000FFFF; regs->CR(3) |= duct_pkrp & DUCT_PKM; /* Restore the PSW key from the DUCT */ regs->psw.pkey = duct_pkrp & DUCT_KEY; /* Restore the problem state bit from the DUCT */ regs->psw.prob = (duct_pkrp & DUCT_PROB) ? 1 : 0; /* Reset the reduced authority bit in the DUCT */ duct_pkrp &= ~DUCT_RA; #if defined(FEATURE_ESAME) ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+20, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+36, regs); #endif /*!defined(FEATURE_ESAME)*/ /* Specification exception if the PSW is now invalid */ if ((regs->psw.IA & 1) #if defined(FEATURE_ESAME) || (regs->psw.amode64 == 0 && regs->psw.amode == 1 && regs->psw.IA > 0x7FFFFFFF) || (regs->psw.amode64 == 0 && regs->psw.amode == 0 && regs->psw.IA > 0x00FFFFFF)) #else /*!defined(FEATURE_ESAME)*/ || (regs->psw.amode == 0 && regs->psw.IA > 0x00FFFFFF)) #endif /*!defined(FEATURE_ESAME)*/ { regs->psw.ilc = 0; ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } } /* end if(BSA-ra) */ INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); #ifdef FEATURE_TRACING /* Update trace table address if branch tracing is on */ if (regs->CR(12) & CR12_BRTRACE) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ #if defined(FEATURE_PER) if( EN_IC_PER_SB(regs) #if defined(FEATURE_PER2) && ( !(regs->CR(9) & CR9_BAC) || PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) ) #endif /*defined(FEATURE_PER2)*/ ) ON_IC_PER_SB(regs); #endif /*defined(FEATURE_PER)*/ } #endif /*defined(FEATURE_BRANCH_AND_SET_AUTHORITY)*/ #if defined(FEATURE_SUBSPACE_GROUP) /*-------------------------------------------------------------------*/ /* B258 BSG - Branch in Subspace Group [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_in_subspace_group) { int r1, r2; /* Values of R fields */ U32 alet; /* Destination subspace ALET */ U32 dasteo; /* Destination ASTE origin */ U32 daste[16]; /* ASN second table entry */ RADR ducto; /* DUCT origin */ U32 duct0; /* DUCT word 0 */ U32 duct1; /* DUCT word 1 */ U32 duct3; /* DUCT word 3 */ RADR abs; /* Absolute address */ VADR newia; /* New instruction address */ int protect = 0; /* 1=ALE protection detected by ART (ignored by BSG) */ U16 xcode; /* Exception code */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); /* Special operation exception if DAT is off or ASF not enabled */ if (REAL_MODE(&(regs->psw)) || !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #ifdef FEATURE_TRACING /* Perform tracing */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_bsg) ((r2 == 0) ? 0 : regs->AR(r2), regs->GR_L(r2), regs); else if (regs->CR(12) & CR12_BRTRACE) newcr12 = ARCH_DEP(trace_br) (regs->GR_L(r2) & 0x80000000, regs->GR_L(r2), regs); #endif /*FEATURE_TRACING*/ /* Load real address of dispatchable unit control table */ ducto = regs->CR(2) & CR2_DUCTO; /* Apply low-address protection to stores into the DUCT */ if (ARCH_DEP(is_low_address_protected) (ducto, 0, regs)) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = (ducto & STORAGE_KEY_PAGEMASK); regs->excarid = 0; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION); } /* Convert DUCT real address to absolute address */ ducto = APPLY_PREFIXING (ducto, regs->PX); /* Program check if DUCT origin address is invalid */ if (ducto >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch DUCT words 0, 1, and 3 from absolute storage (note: the DUCT cannot cross a page boundary) */ duct0 = ARCH_DEP(fetch_fullword_absolute) (ducto, regs); duct1 = ARCH_DEP(fetch_fullword_absolute) (ducto+4, regs); duct3 = ARCH_DEP(fetch_fullword_absolute) (ducto+12, regs); /* Special operation exception if the current primary ASTE origin is not the same as the base ASTE for the dispatchable unit */ if ((regs->CR_L(5) & CR5_PASTEO) != (duct0 & DUCT0_BASTEO)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Obtain the destination ALET from the R2 access register, except that register zero means destination ALET is zero */ alet = (r2 == 0) ? 0 : regs->AR(r2); /* Perform special ALET translation to obtain destination ASTE */ switch (alet) { case ALET_PRIMARY: /* Branch to base space */ /* Load the base space ASTE origin from the DUCT */ dasteo = duct0 & DUCT0_BASTEO; /* Convert the ASTE origin to an absolute address */ abs = APPLY_PREFIXING (dasteo, regs->PX); /* Program check if ASTE origin address is invalid */ if (abs >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch destination ASTE words 2 and 3 from absolute storage (note: the ASTE cannot cross a page boundary) */ daste[2] = ARCH_DEP(fetch_fullword_absolute) (abs+8, regs); daste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs); break; case ALET_SECONDARY: /* Branch to last-used subspace */ /* Load the subspace ASTE origin from the DUCT */ dasteo = duct1 & DUCT1_SSASTEO; /* Special operation exception if SSASTEO is zero */ if (dasteo == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Convert the ASTE origin to an absolute address */ abs = APPLY_PREFIXING (dasteo, regs->PX); /* Program check if ASTE origin address is invalid */ if (abs >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch subspace ASTE words 0, 2, 3, and 5 from absolute storage (note: the ASTE cannot cross a page boundary) */ daste[0] = ARCH_DEP(fetch_fullword_absolute) (abs, regs); daste[2] = ARCH_DEP(fetch_fullword_absolute) (abs+8, regs); daste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs); daste[5] = ARCH_DEP(fetch_fullword_absolute) (abs+20, regs); /* ASTE validity exception if ASTE invalid bit is one */ if (daste[0] & ASTE0_INVALID) { regs->excarid = r2; ARCH_DEP(program_interrupt) (regs, PGM_ASTE_VALIDITY_EXCEPTION); } /* ASTE sequence exception if the subspace ASTE sequence number does not match the sequence number in the DUCT */ if ((daste[5] & ASTE5_ASTESN) != (duct3 & DUCT3_SSASTESN)) { regs->excarid = r2; ARCH_DEP(program_interrupt) (regs, PGM_ASTE_SEQUENCE_EXCEPTION); } break; default: /* ALET not 0 or 1 */ /* Perform special ART to obtain destination ASTE */ xcode = ARCH_DEP(translate_alet) (alet, 0, ACCTYPE_BSG, regs, &dasteo, daste, &protect); /* Program check if ALET translation error */ if (xcode != 0) { regs->excarid = r2; ARCH_DEP(program_interrupt) (regs, xcode); } /* Special operation exception if the destination ASTE is the base space of a different subspace group */ if (dasteo != (duct0 & DUCT0_BASTEO) && ((ASTE_AS_DESIGNATOR(daste) & SSGROUP_BIT) == 0 || (daste[0] & ASTE0_BASE) )) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* end switch(alet) */ /* Update the primary STD (or ASCE) from the destination ASTE */ if ((dasteo == (duct0 & DUCT0_BASTEO)) && (alet != ALET_SECONDARY)) { /* When the destination ASTE is the base space, replace the primary STD (or ASCE) by the STD (or ASCE) in the ASTE */ regs->CR(1) = ASTE_AS_DESIGNATOR(daste); } else { /* When the destination ASTE is a subspace, replace the primary STD or ASCE by the STD or ASTE in the ASTE, except for the space-switch event and storage alteration event bits, which remain unchanged */ regs->CR(1) &= (SSEVENT_BIT | SAEVENT_BIT); regs->CR(1) |= (ASTE_AS_DESIGNATOR(daste) & ~((RADR)(SSEVENT_BIT | SAEVENT_BIT))); } /* Compute the branch address from the R2 operand */ newia = regs->GR(r2); /* If R1 is non-zero, save the current PSW addressing mode and instruction address in the R1 register */ if (r1 != 0) { #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_G(r1) = regs->psw.IA; else #endif /*!defined(FEATURE_ESAME)*/ regs->GR_L(r1) = regs->psw.IA | (regs->psw.amode ? 0x80000000 : 0); } /* Set mode and branch to address specified by R2 operand */ regs->psw.IA = newia; #if defined(FEATURE_ESAME) if (regs->psw.amode64 == 0 && (newia & 0x80000000)) #else /*!defined(FEATURE_ESAME)*/ if (newia & 0x80000000) #endif /*!defined(FEATURE_ESAME)*/ { regs->psw.amode = 1; regs->psw.AMASK = AMASK31; regs->psw.IA = newia & AMASK31; } else { regs->psw.amode = 0; regs->psw.AMASK = AMASK24; regs->psw.IA = newia & AMASK24; } /* Set the SSTD (or SASCE) equal to PSTD (or PASCE) */ regs->CR(7) = regs->CR(1); /* Set SASN equal to PASN */ regs->CR_LHL(3) = regs->CR_LHL(4); /* Reset the subspace fields in the DUCT */ if (alet == ALET_SECONDARY) { /* When the destination ASTE specifies a subspace by means of ALET 1, set the subspace active bit in the DUCT */ duct1 |= DUCT1_SA; ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs); } else if (dasteo == (duct0 & DUCT0_BASTEO)) { /* When the destination ASTE is the base space, reset the subspace active bit in the DUCT */ duct1 &= ~DUCT1_SA; ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs); } else { /* When the destination ASTE specifies a subspace by means of an ALET other than ALET 1, set the subspace active bit and store the subspace ASTE origin in the DUCT */ duct1 = DUCT1_SA | dasteo; ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs); /* Set the subspace ASTE sequence number in the DUCT equal to the destination ASTE sequence number */ duct3 = daste[5]; ARCH_DEP(store_fullword_absolute) (duct3, ducto+12, regs); } #ifdef FEATURE_TRACING /* Update trace table address if ASN tracing or branch tracing */ if (regs->CR(12) & (CR12_ASNTRACE | CR12_BRTRACE)) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); #if defined(FEATURE_PER) if( EN_IC_PER_SB(regs) #if defined(FEATURE_PER2) && ( !(regs->CR(9) & CR9_BAC) || PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) ) #endif /*defined(FEATURE_PER2)*/ ) ON_IC_PER_SB(regs); #endif /*defined(FEATURE_PER)*/ } #endif /*defined(FEATURE_SUBSPACE_GROUP)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B240 BAKR - Branch and Stack Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_stack) { int r1, r2; /* Values of R fields */ VADR n1, n2; /* Operand values */ #ifdef FEATURE_TRACING VADR n = 0; /* Work area */ #endif /*FEATURE_TRACING*/ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_BAKR)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* [5.12.3]/ Fig 10-2 Special operation exception if ASF is not enabled, or if DAT is off, or if not primary-space mode or AR-mode */ if (!ASF_ENABLED(regs) || REAL_MODE(®s->psw) || regs->psw.space == 1) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Obtain the return address and addressing mode from the R1 register, or use updated PSW if R1 is zero */ if ( r1 != 0 ) { n1 = regs->GR(r1); #if defined(FEATURE_ESAME) if ( (n1 & 0x01) == 0 ) n1 &= (n1 & 0x80000000) ? 0xFFFFFFFF : 0x00FFFFFF; #else /*!defined(FEATURE_ESAME)*/ if ( (n1 & 0x80000000) == 0 ) n1 &= 0x00FFFFFF; #endif /*!defined(FEATURE_ESAME)*/ } else { n1 = regs->psw.IA; #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) n1 |= 0x01; else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) n1 |= 0x80000000; } /* Obtain the branch address from the R2 register, or use the updated PSW instruction address if R2 is zero */ n2 = (r2 != 0) ? regs->GR(r2) : regs->psw.IA; n2 &= ADDRESS_MAXWRAP(regs); /* Set the addressing mode bit in the branch address */ #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) n2 |= 0x01; else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) n2 |= 0x80000000; #ifdef FEATURE_TRACING /* Form the branch trace entry */ if((regs->CR(12) & CR12_BRTRACE) && (r2 != 0)) n = ARCH_DEP(trace_br)(regs->psw.amode, regs->GR_L(r2), regs); #endif /*FEATURE_TRACING*/ /* Form the linkage stack entry */ ARCH_DEP(form_stack_entry) (LSED_UET_BAKR, n1, n2, 0, 0, regs); #ifdef FEATURE_TRACING /* Update CR12 to reflect the new branch trace entry */ if((regs->CR(12) & CR12_BRTRACE) && (r2 != 0)) regs->CR(12) = n; #endif /*FEATURE_TRACING*/ /* Execute the branch unless R2 specifies register 0 */ if ( r2 != 0 ) { regs->psw.IA = regs->GR(r2) & ADDRESS_MAXWRAP(regs); #if defined(FEATURE_PER) if( EN_IC_PER_SB(regs) #if defined(FEATURE_PER2) && ( !(regs->CR(9) & CR9_BAC) || PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) ) #endif /*defined(FEATURE_PER2)*/ ) ON_IC_PER_SB(regs); #endif /*defined(FEATURE_PER)*/ } } #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_BROADCASTED_PURGING) /*-------------------------------------------------------------------*/ /* B250 CSP - Compare and Swap and Purge [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_swap_and_purge) { int r1, r2; /* Values of R fields */ U32 n1, n2; /* 32 Bit work */ RADR abs2; /* absolute address of op2 */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); ODD_CHECK(r1, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[0] & SIE_IC0_IPTECSP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_SIE) if(regs->sie_state && regs->sie_scao) { STORAGE_KEY(regs->sie_scao) |= STORKEY_REF; if(sysblk.mainstor[regs->sie_scao] & 0x80) longjmp(regs->progjmp, SIE_INTERCEPT_INST); } #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Obtain 2nd operand address from r2 */ n2 = regs->GR(r2) & 0xFFFFFFFFFFFFFFFCULL & ADDRESS_MAXWRAP(regs); abs2 = LOGICAL_TO_ABS (n2, r2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Load second operand from operand address */ n1 = fetch_fw(sysblk.mainstor + abs2); /* Compare operand with R1 register contents */ if ( regs->GR_L(r1) == n1 ) { /* If equal, store R1+1 at operand location and set cc=0 */ STORE_FW(sysblk.mainstor + abs2, regs->GR_L(r1+1)); regs->psw.cc = 0; /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform requested funtion specified as per request code in r2 */ if (regs->GR_L(r2) & 3) ARCH_DEP(synchronize_broadcast)(regs, regs->GR_L(r2) & 3, 0); } else { /* If unequal, load R1 from operand and set cc=1 */ regs->GR_L(r1) = n1; regs->psw.cc = 1; /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); } /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); } #endif /*defined(FEATURE_BROADCASTED_PURGING)*/ /*-------------------------------------------------------------------*/ /* 83 DIAG - Diagnose */ /*-------------------------------------------------------------------*/ DEF_INST(diagnose) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RS(inst, execflag, regs, r1, r3, b2, effective_addr2); #ifdef FEATURE_HERCULES_DIAGCALLS if ( #if defined(_FEATURE_SIE) !regs->sie_state && #endif /* defined(_FEATURE_SIE) */ effective_addr2 != 0xF08) #endif PRIV_CHECK(regs); SIE_INTERCEPT(regs); /* Process diagnose instruction */ ARCH_DEP(diagnose_call) (effective_addr2, r1, r3, regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); #ifdef FEATURE_HERCULES_DIAGCALLS RETURN_INTCHECK(regs); #endif } #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B226 EPAR - Extract Primary ASN [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_primary_asn) { int r1, r2; /* Values of R fields */ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( regs->psw.prob && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load R1 with PASN from control register 4 bits 16-31 */ regs->GR_L(r1) = regs->CR_LHL(4); } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B227 ESAR - Extract Secondary ASN [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_secondary_asn) { int r1, r2; /* Values of R fields */ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( regs->psw.prob && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load R1 with SASN from control register 3 bits 16-31 */ regs->GR_L(r1) = regs->CR_LHL(3); } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B249 EREG - Extract Stacked Registers [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_stacked_registers) { int r1, r2; /* Values of R fields */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs); /* Load registers from the stack entry */ ARCH_DEP(unstack_registers) (0, lsea, r1, r2, regs); INVALIDATE_AEA_ALL(regs); } #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B24A ESTA - Extract Stacked State [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_stacked_state) { int r1, r2; /* Values of R fields */ BYTE code; /* Extraction code */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ #undef MAX_ESTA_CODE #if defined(FEATURE_ESAME) #define MAX_ESTA_CODE 4 #else /*!defined(FEATURE_ESAME)*/ #define MAX_ESTA_CODE 3 #endif /*!defined(FEATURE_ESAME)*/ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); if (REAL_MODE(®s->psw) || SECONDARY_SPACE_MODE(®s->psw) || !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load the extraction code from low-order byte of R2 register */ code = regs->GR_LHLCL(r2); /* Program check if r1 is odd, or if extraction code is invalid */ if ((r1 & 1) || code > MAX_ESTA_CODE) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs); /* Load general register pair from state entry */ ARCH_DEP(stack_extract) (lsea, r1, code, regs); /* Set condition code depending on entry type */ regs->psw.cc = ((lsed.uet & LSED_UET_ET) == LSED_UET_PC) ? 1 : 0; } #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B224 IAC - Insert Address Space Control [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_address_space_control) { int r1, r2; /* Values of R fields */ RRE(inst, execflag, regs, r1, r2); /* Special operation exception if DAT is off */ if ( REAL_MODE(&(regs->psw)) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Except in XC mode */ && !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC) ) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( regs->psw.prob && !(regs->CR(0) & CR0_EXT_AUTH) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Ignore extraction control in XC mode */ && !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC) ) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Extract the address-space control bits from the PSW */ regs->psw.cc = (regs->psw.armode << 1) | (regs->psw.space); /* Insert address-space mode into register bits 22-23 */ regs->GR_LHLCH(r1) = regs->psw.cc; } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* B20B IPK - Insert PSW Key [S] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_psw_key) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, execflag, regs, b2, effective_addr2); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( regs->psw.prob && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Insert PSW key into bits 24-27 of general register 2 and set bits 28-31 of general register 2 to zero */ regs->GR_LHLCL(2) = regs->psw.pkey & 0xF0; } #if defined(FEATURE_BASIC_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* 09 ISK - Insert Storage Key [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_storage_key) { int r1, r2; /* Values of R fields */ RADR n; /* Absolute storage addr */ #if defined(_FEATURE_SIE) BYTE storkey; #endif /*defined(_FEATURE_SIE)*/ RR(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); #if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE) if( #if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS) regs->sie_state && #endif !(regs->CR(0) & CR0_STORKEY_4K) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif /* Program check if R2 bits 28-31 are not zeroes */ if ( regs->GR_L(r2) & 0x0000000F ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Load 2K block address from R2 register */ n = regs->GR_L(r2) & 0x00FFF800; /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state) { if(regs->siebk->ic[2] & SIE_IC2_ISKE) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE; #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { U16 xcode; int private, protect, stid; RADR rcpa; BYTE rcpkey; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private, &protect, &stid)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX); /* The reference and change byte is located directly beyond the page table and is located at offset 1 in the entry. S/370 mode cannot be emulated in ESAME mode, so no provision is made for ESAME mode tables */ rcpa += 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = sysblk.mainstor[rcpa]; STORAGE_KEY(rcpa) |= STORKEY_REF; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE); /* guest absolute to host real */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private, &protect, &stid)) #if defined(_FEATURE_STORAGE_KEY_ASSIST) { /* In case of storage key assist obtain the key and fetch bit from the PGSTE */ if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA) regs->GR_LHLCL(r1) = storkey | (sysblk.mainstor[rcpa-1] & (STORKEY_KEY | STORKEY_FETCH)); else longjmp(regs->progjmp, SIE_INTERCEPT_INST); } else #else /*!defined(_FEATURE_STORAGE_KEY_ASSIST)*/ longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(n, regs->hostregs->PX); #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = storkey | (STORAGE_KEY(n) & 0xFE); #else regs->GR_LHLCL(r1) = storkey | ((STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE); #endif } } } else /* !sie_pref */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE; #endif } else /* !sie_state */ #endif /*defined(_FEATURE_SIE)*/ /* Insert the storage key into R1 register bits 24-31 */ #if defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE; #endif /* In BC mode, clear bits 29-31 of R1 register */ if ( regs->psw.ecmode == 0 ) regs->GR_LHLCL(r1) &= 0xF8; // /*debug*/logmsg("ISK storage block %8.8X key %2.2X\n", // regs->GR_L(r2), regs->GR_L(r1) & 0xFE); } #endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/ #if defined(FEATURE_EXTENDED_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B229 ISKE - Insert Storage Key Extended [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_storage_key_extended) { int r1, r2; /* Values of R fields */ RADR n; /* Workarea */ #if defined(_FEATURE_SIE) BYTE storkey; #endif /*defined(_FEATURE_SIE)*/ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); /* Load 4K block address from R2 register */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state) { if(regs->siebk->ic[2] & SIE_IC2_ISKE) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE; #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { U16 xcode; int private, protect, stid; RADR rcpa; BYTE rcpkey; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private, &protect, &stid)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(regs->siebk->mx & SIE_MX_XC) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = sysblk.mainstor[rcpa]; STORAGE_KEY(rcpa) |= STORKEY_REF; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE); /* guest absolute to host real */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private, &protect, &stid)) #if defined(_FEATURE_STORAGE_KEY_ASSIST) { /* In case of storage key assist obtain the key and fetch bit from the PGSTE */ if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA) regs->GR_LHLCL(r1) = storkey | (sysblk.mainstor[rcpa-1] & (STORKEY_KEY | STORKEY_FETCH)); else longjmp(regs->progjmp, SIE_INTERCEPT_INST); } else #else /*!defined(_FEATURE_STORAGE_KEY_ASSIST)*/ longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(n, regs->hostregs->PX); /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = storkey | (STORAGE_KEY(n) & 0xFE); #else regs->GR_LHLCL(r1) = storkey | ((STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE); #endif } } } else /* sie_pref */ /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE; #endif } else /* !sie_state */ #endif /*defined(_FEATURE_SIE)*/ /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n) | STORAGE_KEY2(n)) & 0xFE; #endif } /* end DEF_INST(insert_storage_key_extended) */ #endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ /*-------------------------------------------------------------------*/ /* B223 IVSK - Insert Virtual Storage Key [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_virtual_storage_key) { int r1, r2; /* Values of R fields */ VADR effective_addr; /* Virtual storage addr */ U16 xcode; /* Exception code */ int private; /* 1=Private address space */ int protect; /* 1=ALE or page protection */ int stid; /* Segment table indication */ RADR n; /* 32-bit operand values */ #if defined(_FEATURE_STORAGE_KEY_ASSIST) int sr; /* SIE_TRANSLATE_ADDR rc */ #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ RRE(inst, execflag, regs, r1, r2); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( regs->psw.prob && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load virtual storage address from R2 register */ effective_addr = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Translate virtual address to real address */ if (ARCH_DEP(translate_addr) (effective_addr, r2, regs, ACCTYPE_IVSK, &n, &xcode, &private, &protect, &stid)) ARCH_DEP(program_interrupt) (regs, xcode); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_STORAGE_KEY_ASSIST) /* When running under SIE, and the guest absolute address is paged out, then obtain the storage key from the SPGTE rather then causing a host page fault. */ if(regs->sie_state && !regs->sie_pref && ((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && !(regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY)) { /* guest absolute to host absolute addr or PTE addr in case of rc2 */ sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private, &protect, &stid); n = APPLY_PREFIXING (n, regs->hostregs->PX); if(sr != 0 && sr != 2) ARCH_DEP(program_interrupt) (regs->hostregs, xcode); if(sr == 2) { /* For ESA/390 the RCP byte entry is at offset 0 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ n += regs->hostregs->arch_mode == ARCH_900 ? 2048 : 1024; /* Insert PGSTE key bits 0-4 into R1 register bits 56-60 and set bits 61-63 to zeroes */ regs->GR_LHLCL(r1) = sysblk.mainstor[n] & 0xF8; } else /* Insert storage key bits 0-4 into R1 register bits 56-60 and set bits 61-63 to zeroes */ regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xF8; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); /* Insert storage key bits 0-4 into R1 register bits 56-60 and set bits 61-63 to zeroes */ regs->GR_LHLCL(r1) = STORAGE_KEY(n) & 0xF8; } } /* end DEF_INST(insert_virtual_storage_key) */ /*-------------------------------------------------------------------*/ /* B221 IPTE - Invalidate Page Table Entry [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(invalidate_page_table_entry) { int r1, r2; /* Values of R fields */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[0] & SIE_IC0_IPTECSP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before operation */ PERFORM_SERIALIZATION (regs); OBTAIN_MAINLOCK(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && regs->sie_scao) { STORAGE_KEY(regs->sie_scao) |= STORKEY_REF; if(sysblk.mainstor[regs->sie_scao] & 0x80) { RELEASE_MAINLOCK(regs); longjmp(regs->progjmp, SIE_INTERCEPT_INST); } sysblk.mainstor[regs->sie_scao] |= 0x80; STORAGE_KEY(regs->sie_scao) |= (STORKEY_REF|STORKEY_CHANGE); } #endif /*defined(_FEATURE_SIE)*/ /* Invalidate page table entry */ ARCH_DEP(invalidate_pte) (inst[1], r1, r2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && regs->sie_scao) { sysblk.mainstor[regs->sie_scao] &= 0x7F; STORAGE_KEY(regs->sie_scao) |= (STORKEY_REF|STORKEY_CHANGE); } #endif /*defined(_FEATURE_SIE)*/ /* Mainlock now released by `invalidate_pte' */ // RELEASE_MAINLOCK(regs); } #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* E500 LASP - Load Address Space Parameters [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_address_space_parameters) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ U64 dreg; U16 pkm_d; U16 sasn_d; U16 ax_d; U16 pasn_d; U32 aste[16]; /* ASN second table entry */ RADR pstd; /* Primary STD */ RADR sstd; /* Secondary STD */ U32 ltd; /* Linkage table designation */ U32 pasteo; /* Primary ASTE origin */ U32 sasteo; /* Secondary ASTE origin */ U16 ax; /* Authorisation index */ #ifdef FEATURE_SUBSPACE_GROUP U16 xcode; /* Exception code */ #endif /*FEATURE_SUBSPACE_GROUP*/ SSE(inst, execflag, regs, b1, effective_addr1, b2, effective_addr2); SIE_MODE_XC_OPEX(regs); PRIV_CHECK(regs); /* Special operation exception if ASN translation control (bit 12 of control register 14) is zero */ if ( (regs->CR(14) & CR14_ASN_TRAN) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); DW_CHECK(effective_addr1, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_LASP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Fetch PKM, SASN, AX, and PASN from first operand */ dreg = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); pkm_d = (dreg >> 48) & 0xFFFF; sasn_d = (dreg >> 32) & 0xFFFF; ax_d = (dreg >> 16) & 0xFFFF; pasn_d = dreg & 0xFFFF; INVALIDATE_AEA_ALL(regs); /* PASN translation */ /* Perform PASN translation if PASN not equal to current PASN, or if LASP function bit 29 is set */ if ((effective_addr2 & 0x00000004) || pasn_d != regs->CR_LHL(4) ) { /* Translate PASN and return condition code 1 if AFX- or ASX-translation exception condition */ if (ARCH_DEP(translate_asn) (pasn_d, regs, &pasteo, aste)) { regs->psw.cc = 1; return; } INVALIDATE_AIA(regs); /* Obtain new PSTD and LTD from ASTE */ pstd = ASTE_AS_DESIGNATOR(aste); ltd = ASTE_LT_DESIGNATOR(aste); ax = (aste[1] & ASTE1_AX) >> 16; #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, &xcode, regs); /* Return with condition code 1 if ASTE exception recognized */ if (xcode != 0) { regs->psw.cc = 1; return; } #endif /*FEATURE_SUBSPACE_GROUP*/ /* Return with condition code 3 if either current STD or new STD indicates a space switch event */ if ((regs->CR(1) & SSEVENT_BIT) || (ASTE_AS_DESIGNATOR(aste) & SSEVENT_BIT)) { regs->psw.cc = 3; return; } } else { /* Load current PSTD and LTD or PASTEO */ pstd = regs->CR(1); ltd = regs->CR_L(5); pasteo = regs->CR_L(5); ax = (regs->CR(4) & CR4_AX) >> 16; } /* If bit 30 of the LASP function bits is zero, use the current AX instead of the AX specified in the first operand */ if ((effective_addr2 & 0x00000002)) ax = ax_d; /* SASN translation */ /* If new SASN = new PASN then set new SSTD = new PSTD */ if (sasn_d == pasn_d) { sstd = pstd; } else { /* If new SASN = current SASN, and bit 29 of the LASP function bits is 0, and bit 31 of the LASP function bits is 1, use current SSTD in control register 7 */ if (!(effective_addr2 & 0x00000004) && (effective_addr2 & 0x00000001) && (sasn_d == regs->CR_LHL(3))) { sstd = regs->CR(7); } else { /* Translate SASN and return condition code 2 if AFX- or ASX-translation exception condition */ if (ARCH_DEP(translate_asn) (sasn_d, regs, &sasteo, aste)) { regs->psw.cc = 2; return; } /* Obtain new SSTD or SASCE from secondary ASTE */ sstd = ASTE_AS_DESIGNATOR(aste); #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new SSTD */ sstd = ARCH_DEP(subspace_replace) (sstd, sasteo, &xcode, regs); /* Return condition code 2 if ASTE exception recognized */ if (xcode != 0) { regs->psw.cc = 2; return; } #endif /*FEATURE_SUBSPACE_GROUP*/ /* Perform SASN authorization if bit 31 of the LASP function bits is 0 */ if (!(effective_addr2 & 0x00000001)) { /* Condition code 2 if SASN authorization fails */ if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY, regs)) { regs->psw.cc = 2; return; } } /* end if(SASN authorization) */ } /* end if(SASN translation) */ } /* end if(SASN = PASN) */ /* Perform control-register loading */ regs->CR(1) = pstd; regs->CR_LHH(3) = pkm_d; regs->CR_LHL(3) = sasn_d; regs->CR_LHH(4) = ax; regs->CR_LHL(4) = pasn_d; regs->CR_L(5) = ASF_ENABLED(regs) ? pasteo : ltd; regs->CR(7) = sstd; /* Return condition code zero */ regs->psw.cc = 0; } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* B7 LCTL - Load Control [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(load_control) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, d; /* Integer work areas */ BYTE rwork[64]; /* Register work areas */ #if defined(FEATURE_CHANNEL_SUBSYSTEM) BYTE dism; /* Disabled int subcl mask */ #elif defined(FEATURE_S370_CHANNEL) U32 dchn; /* Disabled channel mask */ #endif RS(inst, execflag, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); FW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state) { U32 n; for(i = r1; ; ) { n = 0x8000 >> i; if(regs->siebk->lctl_ctl[i < 8 ? 0 : 1] & ((i < 8) ? n >> 8 : n)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if ( i == r3 ) break; i++; i &= 15; } } #endif /*defined(_FEATURE_SIE)*/ /* Calculate the number of bytes to be loaded */ d = (((r3 < r1) ? r3 + 16 - r1 : r3 - r1) + 1) * 4; /* Fetch new control register contents from operand address */ ARCH_DEP(vfetchc) ( rwork, d-1, effective_addr2, b2, regs ); INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); #if defined(FEATURE_CHANNEL_SUBSYSTEM) /* Save disabled I/O subclasses */ dism = ~regs->CR_LHHCH(6); #elif defined(FEATURE_S370_CHANNEL) /* Save disabled channel mask */ dchn = ~regs->CR_L(2); #endif /* Load control registers from work area */ for ( i = r1, d = 0; ; ) { /* Load control register bits 32-63 from work area */ FETCH_FW(regs->CR_L(i), rwork + d); d += 4; /* Instruction is complete when r3 register is done */ if ( i == r3 ) break; /* Update register number, wrapping from 15 to 0 */ i++; i &= 15; } #if defined(FEATURE_CHANNEL_SUBSYSTEM) /* Force I/O interrupt check when enabling an I/O subclass */ if(dism & regs->CR_LHHCH(6)) #elif defined(FEATURE_S370_CHANNEL) if(dchn & regs->CR_L(2)); #endif { obtain_lock(&sysblk.intlock); ON_IC_IOPENDING; release_lock(&sysblk.intlock); } SET_IC_EXTERNAL_MASK(regs); SET_IC_MCK_MASK(regs); SET_IC_PER_MASK(regs); RETURN_INTCHECK(regs); } /* end DEF_INST(load_control) */ /*-------------------------------------------------------------------*/ /* 82 LPSW - Load Program Status Word [S] */ /*-------------------------------------------------------------------*/ DEF_INST(load_program_status_word) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ DWORD dword; int rc; #if defined(FEATURE_ESAME) int amode64; #endif /*defined(FEATURE_ESAME)*/ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_LPSW)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Fetch new PSW from operand address */ ARCH_DEP(vfetchc) ( dword, 8-1, effective_addr2, b2, regs ); /* Load updated PSW (ESA/390 Format in ESAME mode) */ #if defined(FEATURE_ESAME) /* save amode64 flag */ amode64 = dword[3] & 0x01; /* make psw valid for esa390 mode */ dword[3] &= ~0x01; if ( ( rc = s390_load_psw ( regs, dword ) ) ) { regs->psw.notesame = 0; #else /*!defined(FEATURE_ESAME)*/ if ( ( rc = ARCH_DEP(load_psw) ( regs, dword ) ) ) { #endif /*!defined(FEATURE_ESAME)*/ ARCH_DEP(program_interrupt) (regs, rc); } /* load_psw() has set the ILC to zero. This needs to be reset to 4 for an eventual PER event */ regs->psw.ilc = 4; #if defined(FEATURE_ESAME) /* Set the notesame bit to zero as it has been set, and clear the high word of the instruction address, as it has not been touched by s390_load_psw */ regs->psw.notesame = 0; regs->psw.amode64 = amode64; regs->psw.IA_H = 0; #endif /*defined(FEATURE_ESAME)*/ /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); RETURN_INTCHECK(regs); } /* end DEF_INST(load_program_status_word) */ /*-------------------------------------------------------------------*/ /* B1 LRA - Load Real Address [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load_real_address) { int r1; /* Register number */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U16 xcode; /* Exception code */ int private; /* 1=Private address space */ int protect; /* 1=ALE or page protection */ int stid; /* Segment table indication */ int cc; /* Condition code */ RADR n; /* 32-bit operand values */ RX(inst, execflag, regs, r1, b2, effective_addr2); SIE_MODE_XC_OPEX(regs); PRIV_CHECK(regs); /* Translate the effective address to a real address */ cc = ARCH_DEP(translate_addr) (effective_addr2, b2, regs, ACCTYPE_LRA, &n, &xcode, &private, &protect, &stid); /* If ALET exception or ASCE-type or region translation exception, set exception code in R1 bits 48-63, set bit 32 of R1, and set condition code 3 */ if (cc > 3) { regs->GR_L(r1) = 0x80000000 | xcode; cc = 3; } else { /* Set r1 and condition code as returned by translate_addr */ #if defined(FEATURE_ESAME) if (regs->psw.amode64 && cc != 3) { regs->GR_G(r1) = n; } else { if (n <= 0x7FFFFFFF) { regs->GR_L(r1) = n; } else { /* Special handling if in 24-bit or 31-bit mode and the returned address exceeds 2GB, or if cc=3 and the returned address exceeds 2GB */ if (cc == 0) { /* Real address exceeds 2GB */ ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* Condition code is 1, 2, or 3, and the returned table entry address exceeds 2GB. Convert to condition code 3 and return the exception code which will be X'0010' or X'0011' */ regs->GR_L(r1) = 0x80000000 | xcode; cc = 3; } /* end else(n) */ } /* end else(amode) */ #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(r1) = n; #endif /*!defined(FEATURE_ESAME)*/ } /* end else(cc) */ regs->psw.cc = cc; } /* end DEF_INST(load_real_address) */ /*-------------------------------------------------------------------*/ /* B24B LURA - Load Using Real Address [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_using_real_address) { int r1, r2; /* Values of R fields */ RADR n; /* Unsigned work */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); /* R2 register contains operand real storage address */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Program check if operand not on fullword boundary */ FW_CHECK(n, regs); /* Load R1 register from second operand */ regs->GR_L(r1) = ARCH_DEP(vfetch4) ( n, USE_REAL_ADDR, regs ); } #if defined(FEATURE_LOCK_PAGE) /*-------------------------------------------------------------------*/ /* B262 LKPG - Lock Page [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(lock_page) { int r1, r2; /* Values of R fields */ VADR n2; /* effective addr of r2 */ RADR raddr, /* Real address */ rpte; /* PTE real address */ CREG pte; /* Page Table Entry */ int private; /* 1=Private address space */ int protect; /* 1=ALE or page protection */ int stid; /* Segment table indication */ U16 xcode = 0; /* Exception code */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); if(REAL_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); if(regs->GR_L(0) & LKPG_GPR0_RESV) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); n2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Access to PTE must be serialized */ OBTAIN_MAINLOCK(regs); /* Return condition code 3 if translation exception */ ARCH_DEP(translate_addr) (n2, r2, regs, ACCTYPE_PTE, &rpte, &xcode, &private, &protect, &stid); if (xcode == 0) { rpte = APPLY_PREFIXING (rpte, regs->PX); pte = #if defined(FEATURE_ESAME) ARCH_DEP(fetch_doubleword_absolute) (rpte, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(fetch_fullword_absolute) (rpte, regs); #endif /*!defined(FEATURE_ESAME)*/ if(regs->GR_L(0) & LKPG_GPR0_LOCKBIT) { /* Lock request */ if(!(pte & PAGETAB_PGLOCK)) { /* Return condition code 3 if translation exception */ if(ARCH_DEP(translate_addr) (n2, r2, regs, ACCTYPE_LRA, &raddr, &xcode, &private, &protect, &stid)) { regs->psw.cc = 3; RELEASE_MAINLOCK(regs); return; } pte |= PAGETAB_PGLOCK; #if defined(FEATURE_ESAME) ARCH_DEP(store_doubleword_absolute) (pte, rpte, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(store_fullword_absolute) (pte, rpte, regs); #endif /*!defined(FEATURE_ESAME)*/ regs->GR(r1) = raddr; regs->psw.cc = 0; } else regs->psw.cc = 1; } else { /* Unlock reguest */ if(pte & PAGETAB_PGLOCK) { pte &= ~((U64)PAGETAB_PGLOCK); #if defined(FEATURE_ESAME) ARCH_DEP(store_doubleword_absolute) (pte, rpte, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(store_fullword_absolute) (pte, rpte, regs); #endif /*!defined(FEATURE_ESAME)*/ regs->psw.cc = 0; } else regs->psw.cc = 1; } } else regs->psw.cc = 3; RELEASE_MAINLOCK(regs); } /* end DEF_INST(lock_page) */ #endif /*defined(FEATURE_LOCK_PAGE)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B247 MSTA - Modify Stacked State [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(modify_stacked_state) { int r1, unused; /* Values of R fields */ U32 m1, m2; /* Modify values */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ RRE(inst, execflag, regs, r1, unused); SIE_MODE_XC_OPEX(regs); if (REAL_MODE(®s->psw) || SECONDARY_SPACE_MODE(®s->psw) || !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); ODD_CHECK(r1, regs); /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs); /* Load values from rightmost 32 bits of R1 and R1+1 registers */ m1 = regs->GR_L(r1); m2 = regs->GR_L(r1+1); /* Store two 32-bit values into modifiable area of state entry */ ARCH_DEP(stack_modify) (lsea, m1, m2, regs); } #endif /*defined(FEATURE_LINKAGE_STACK)*/ /*-------------------------------------------------------------------*/ /* DA MVCP - Move to Primary [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_to_primary) { int r1, r3; /* Register numbers */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ int k; /* Integer workarea */ GREG l; /* Unsigned workarea */ SS(inst, execflag, regs, r1, r3, b1, effective_addr1, b2, effective_addr2); SIE_MODE_XC_OPEX(regs); /* Program check if secondary space control (CR0 bit 5) is 0, or if DAT is off, or if in AR mode or home-space mode */ if ((regs->CR(0) & CR0_SEC_SPACE) == 0 || REAL_MODE(®s->psw) || regs->psw.armode) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load true length from R1 register */ l = GR_A(r1,regs); /* If the true length does not exceed 256, set condition code zero, otherwise set cc=3 and use effective length of 256 */ if (l <= 256) cc = 0; else { cc = 3; l = 256; } /* Load secondary space key from R3 register bits 24-27 */ k = regs->GR_L(r3) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( regs->psw.prob && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters from secondary address space to primary address space using secondary key for second operand */ if (l > 0) ARCH_DEP(move_chars) (effective_addr1, USE_PRIMARY_SPACE, regs->psw.pkey, effective_addr2, USE_SECONDARY_SPACE, k, l-1, regs); /* Set condition code */ regs->psw.cc = cc; } /*-------------------------------------------------------------------*/ /* DB MVCS - Move to Secondary [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_to_secondary) { int r1, r3; /* Register numbers */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ int k; /* Integer workarea */ GREG l; /* Unsigned workarea */ SS(inst, execflag, regs, r1, r3, b1, effective_addr1, b2, effective_addr2); SIE_MODE_XC_OPEX(regs); /* Program check if secondary space control (CR0 bit 5) is 0, or if DAT is off, or if in AR mode or home-space mode */ if ((regs->CR(0) & CR0_SEC_SPACE) == 0 || REAL_MODE(®s->psw) || regs->psw.armode) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load true length from R1 register */ l = GR_A(r1,regs); /* If the true length does not exceed 256, set condition code zero, otherwise set cc=3 and use effective length of 256 */ if (l <= 256) cc = 0; else { cc = 3; l = 256; } /* Load secondary space key from R3 register bits 24-27 */ k = regs->GR_L(r3) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( regs->psw.prob && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters from primary address space to secondary address space using secondary key for first operand */ if (l > 0) ARCH_DEP(move_chars) (effective_addr1, USE_SECONDARY_SPACE, k, effective_addr2, USE_PRIMARY_SPACE, regs->psw.pkey, l-1, regs); /* Set condition code */ regs->psw.cc = cc; } /*-------------------------------------------------------------------*/ /* E50F MVCDK - Move with Destination Key [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_destination_key) { int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int k, l; /* Integer workarea */ SSE(inst, execflag, regs, b1, effective_addr1, b2, effective_addr2); /* Load operand length-1 from register 0 bits 24-31 */ l = regs->GR_L(0) & 0xFF; /* Load destination key from register 1 bits 24-27 */ k = regs->GR_L(1) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( regs->psw.prob && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters using destination key for operand 1 */ ARCH_DEP(move_chars) (effective_addr1, b1, k, effective_addr2, b2, regs->psw.pkey, l, regs); } /*-------------------------------------------------------------------*/ /* D9 MVCK - Move with Key [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_key) { int r1, r3; /* Register numbers */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ int k; /* Integer workarea */ GREG l; /* Unsigned workarea */ SS(inst, execflag, regs, r1, r3, b1, effective_addr1, b2, effective_addr2); /* Load true length from R1 register */ l = GR_A(r1,regs); /* If the true length does not exceed 256, set condition code zero, otherwise set cc=3 and use effective length of 256 */ if (l <= 256) cc = 0; else { cc = 3; l = 256; } /* Load source key from R3 register bits 24-27 */ k = regs->GR_L(r3) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( regs->psw.prob && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters using source key for second operand */ if (l > 0) ARCH_DEP(move_chars) (effective_addr1, b1, regs->psw.pkey, effective_addr2, b2, k, l-1, regs); /* Set condition code */ regs->psw.cc = cc; } /*-------------------------------------------------------------------*/ /* E50E MVCSK - Move with Source Key [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_source_key) { int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int k, l; /* Integer workarea */ SSE(inst, execflag, regs, b1, effective_addr1, b2, effective_addr2); /* Load operand length-1 from register 0 bits 24-31 */ l = regs->GR_L(0) & 0xFF; /* Load source key from register 1 bits 24-27 */ k = regs->GR_L(1) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( regs->psw.prob && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters using source key for second operand */ ARCH_DEP(move_chars) (effective_addr1, b1, regs->psw.pkey, effective_addr2, b2, k, l, regs); } #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B218 PC - Program Call [S] */ /*-------------------------------------------------------------------*/ DEF_INST(program_call) { int b2; /* Base of effective addr */ U32 pcnum; /* Program call number */ VADR effective_addr2; /* Effective address */ RADR abs; /* Absolute address */ RADR pstd; /* Primary STD or ASCE */ U32 oldpstd; /* Old Primary STD or ASCE */ U32 ltd; /* Linkage table designation */ U32 pasteo; /* Primary ASTE origin */ RADR lto; /* Linkage table origin */ int ltl; /* Linkage table length */ U32 lte; /* Linkage table entry */ RADR eto; /* Entry table origin */ int etl; /* Entry table length */ U32 ete[8]; /* Entry table entry */ int numwords; /* ETE size (4 or 8 words) */ int i; /* Array subscript */ int ssevent = 0; /* 1=space switch event */ U32 aste[16]; /* ASN second table entry */ U32 akm; /* Bits 0-15=AKM, 16-31=zero */ U16 xcode; /* Exception code */ U16 pasn; /* Primary ASN */ U16 oldpasn; /* Old Primary ASN */ #if defined(FEATURE_LINKAGE_STACK) U32 csi; /* Called-space identifier */ VADR retn; /* Return address and amode */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ S(inst, execflag, regs, b2, effective_addr2); SIE_MODE_XC_OPEX(regs); INVALIDATE_AEA_ALL(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_PC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Load the PC number from the low-order 20 bits of the operand */ pcnum = effective_addr2 & (PC_LX | PC_EX); /* Special operation exception if DAT is off, or if in secondary space mode or home space mode */ if (REAL_MODE(&(regs->psw)) || regs->psw.space == 1) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* save CR4 and CR1 incase of space switch */ oldpasn = regs->CR(4) & CR4_PASN; oldpstd = regs->CR(1); /* [5.5.3.1] Load the linkage table designation */ if (!ASF_ENABLED(regs)) { /* Special operation exception if in AR mode */ if (ACCESS_REGISTER_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Obtain the LTD from control register 5 */ ltd = regs->CR_L(5); } else { /* Obtain the primary ASTE origin from control register 5 */ pasteo = regs->CR_L(5) & CR5_PASTEO; /* Convert the PASTE origin to an absolute address */ abs = APPLY_PREFIXING (pasteo, regs->PX); /* Program check if PASTE is outside main storage */ if (abs >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch primary ASTE words 3 or 6 from absolute storage (note: the ASTE cannot cross a page boundary) */ #if !defined(FEATURE_ESAME) aste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs); #else /*defined(FEATURE_ESAME)*/ aste[6] = ARCH_DEP(fetch_fullword_absolute) (abs+24, regs); #endif /*defined(FEATURE_ESAME)*/ /* Load LTD from primary ASTE word 3 or 6 */ ltd = ASTE_LT_DESIGNATOR(aste); } #ifdef FEATURE_TRACING /* Form trace entry if ASN tracing is active */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_pc) (pcnum, regs); #endif /*FEATURE_TRACING*/ /* Special operation exception if subsystem linkage control bit in linkage table designation is zero */ if ((ltd & LTD_SSLINK) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* [5.5.3.2] Linkage table lookup */ /* Extract the linkage table origin and length from the LTD */ lto = ltd & LTD_LTO; ltl = ltd & LTD_LTL; /* Program check if linkage index is outside the linkage table */ if (ltl < ((pcnum & PC_LX) >> 13)) { regs->TEA = pcnum; ARCH_DEP(program_interrupt) (regs, PGM_LX_TRANSLATION_EXCEPTION); } /* Calculate the address of the linkage table entry */ lto += (pcnum & PC_LX) >> 6; lto &= 0x7FFFFFFF; /* Program check if linkage table entry is outside real storage */ if (lto >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch linkage table entry from real storage. All bytes must be fetched concurrently as observed by other CPUs */ lto = APPLY_PREFIXING (lto, regs->PX); lte = ARCH_DEP(fetch_fullword_absolute)(lto, regs); /* Program check if linkage entry invalid bit is set */ if (lte & LTE_INVALID) { regs->TEA = pcnum; ARCH_DEP(program_interrupt) (regs, PGM_LX_TRANSLATION_EXCEPTION); } /* [5.5.3.3] Entry table lookup */ /* Extract the entry table origin and length from the LTE */ eto = lte & LTE_ETO; etl = lte & LTE_ETL; /* Program check if entry index is outside the entry table */ if (etl < ((pcnum & PC_EX) >> 2)) { regs->TEA = pcnum; ARCH_DEP(program_interrupt) (regs, PGM_EX_TRANSLATION_EXCEPTION); } /* Calculate the starting address of the entry table entry */ eto += (pcnum & PC_EX) << (ASF_ENABLED(regs) ? 5 : 4); eto &= 0x7FFFFFFF; /* Determine the size of the entry table entry */ numwords = ASF_ENABLED(regs) ? 8 : 4; /* Fetch the 4- or 8-word entry table entry from real storage. Each fullword of the ETE must be fetched concurrently as observed by other CPUs. The entry table cannot cross a page boundary. */ for (i = 0; i < numwords; i++) { /* Program check if address is outside main storage */ abs = APPLY_PREFIXING (eto, regs->PX); if (abs >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch one word of the entry table entry */ ete[i] = ARCH_DEP(fetch_fullword_absolute) (abs, regs); eto += 4; eto &= 0x7FFFFFFF; } /* Clear remaining words if fewer than 8 words were loaded */ while (i < 8) ete[i++] = 0; /* Program check if basic program call in AR mode */ if ((ete[4] & ETE4_T) == 0 && regs->psw.armode) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #if defined(FEATURE_ESAME) /* Program check if basic program call is attempting to switch into or out of 64-bit addressing mode */ if ((ete[4] & ETE4_T) == 0 && ((ete[4] & ETE4_G) ? 1 : 0) != regs->psw.amode64) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif /*defined(FEATURE_ESAME)*/ /* Program check if resulting addressing mode is 24 and the entry instruction address is not a 24-bit address */ if ((ete[1] & ETE1_AMODE) == 0 #if defined(FEATURE_ESAME) && (ete[4] & ETE4_G) == 0 #endif /*defined(FEATURE_ESAME)*/ && (ete[1] & ETE1_EIA) > 0x00FFFFFF) ARCH_DEP(program_interrupt) (regs, PGM_PC_TRANSLATION_SPECIFICATION_EXCEPTION); /* Obtain the authorization key mask from the entry table */ #if defined(FEATURE_ESAME) akm = ete[2] & ETE2_AKM; #else /*!defined(FEATURE_ESAME)*/ akm = ete[0] & ETE0_AKM; #endif /*!defined(FEATURE_ESAME)*/ /* Program check if in problem state and the PKM in control register 3 produces zero when ANDed with the AKM in the ETE */ if (regs->psw.prob && ((regs->CR(3) & CR3_KEYMASK) & akm) == 0) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Obtain the new primary ASN from the entry table */ #if defined(FEATURE_ESAME) pasn = ete[2] & ETE2_ASN; #else /*!defined(FEATURE_ESAME)*/ pasn = ete[0] & ETE0_ASN; #endif /*!defined(FEATURE_ESAME)*/ /* Obtain the ASTE if ASN is non-zero */ if (pasn != 0) { INVALIDATE_AIA(regs); /* Program check if ASN translation control is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* For ESA/390 when ASF control is not enabled, the ASTE is obtained by ASN translation. For ESAME, and for ESA/390 when ASF control is enabled, the ASTE is loaded using the ASTE real address from the entry table */ if (!ASF_ENABLED(regs)) { /* Perform ASN translation to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (pasn, regs, &pasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (regs, xcode); } else { /* Load the ASTE origin from the entry table */ pasteo = ete[5] & ETE5_ASTE; /* Convert the ASTE origin to an absolute address */ abs = APPLY_PREFIXING (pasteo, regs->PX); /* Program check if ASTE origin address is invalid */ if (abs >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch the 16-word ASTE from absolute storage (note: the ASTE cannot cross a page boundary) */ for (i = 0; i < 16; i++) { aste[i] = ARCH_DEP(fetch_fullword_absolute) (abs, regs); abs += 4; } /* ASX translation exception if ASTE invalid bit is one */ if (aste[0] & ASTE0_INVALID) { regs->TEA = pasn; ARCH_DEP(program_interrupt) (regs, PGM_ASX_TRANSLATION_EXCEPTION); } } /* Obtain the new PSTD or PASCE from the ASTE */ pstd = ASTE_AS_DESIGNATOR(aste); #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, NULL, regs); #endif /*FEATURE_SUBSPACE_GROUP*/ } /* end if(PC-ss) */ else { /* PC-cp */ /* For PC to current primary, load current primary STD */ pstd = regs->CR(1); } /* end if(PC-cp) */ /* Perform basic or stacking program call */ if ((ete[4] & ETE4_T) == 0) { /* For basic PC, load linkage info into general register 14 */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_G(14) = regs->psw.IA | regs->psw.prob; else regs->GR_L(14) = (regs->psw.amode ? 0x80000000 : 0) | regs->psw.IA | regs->psw.prob; #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(14) = (regs->psw.amode ? 0x80000000 : 0) | regs->psw.IA | regs->psw.prob; #endif /*!defined(FEATURE_ESAME)*/ /* Update the PSW from the entry table */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->psw.IA = ((U64)(ete[0]) << 32) | (U64)(ete[1] & 0xFFFFFFFE); else { regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; regs->psw.IA = ete[1] & ETE1_EIA; } #else /*!defined(FEATURE_ESAME)*/ regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; regs->psw.IA = ete[1] & ETE1_EIA; #endif /*!defined(FEATURE_ESAME)*/ regs->psw.prob = (ete[1] & ETE1_PROB) ? 1 : 0; /* Load the current PKM and PASN into general register 3 */ regs->GR_L(3) = (regs->CR(3) & CR3_KEYMASK) | (regs->CR(4) & CR4_PASN); /* OR the EKM into the current PKM */ regs->CR(3) |= (ete[3] & ETE3_EKM); /* Load the entry parameter into general register 4 */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_H(4) = ete[6]; regs->GR_L(4) = ete[7]; #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(4) = ete[2]; #endif /*!defined(FEATURE_ESAME)*/ } /* end if(basic PC) */ else #if defined(FEATURE_LINKAGE_STACK) { /* stacking PC */ /* ESA/390 POP Fig 10-17 8.B.11 */ if (!ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && regs->psw.amode64 != (ete[4] & ETE4_G) ? 1 : 0) ARCH_DEP(trace_ms) (0,((U64)(ete[0]) << 32) | (U64)(ete[1] & 0xFFFFFFFE), regs); #endif /*defined(FEATURE_ESAME)*/ /* Set the called-space identification */ csi = (pasn == 0) ? 0 : pasn << 16 | (aste[5] & 0x0000FFFF); /* Set the addressing mode bits in the return address */ retn = regs->psw.IA; #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) retn |= 0x01; else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) retn |= 0x80000000; #if defined(FEATURE_ESAME) /* Set the high-order bit of the PC number if the resulting addressing mode is 64-bit */ if (ete[4] & ETE4_G) pcnum |= 0x80000000; #endif /*defined(FEATURE_ESAME)*/ /* Perform the stacking process */ ARCH_DEP(form_stack_entry) (LSED_UET_PC, retn, 0, csi, pcnum, regs); /* Update the PSW from the entry table */ #if defined(FEATURE_ESAME) if (ete[4] & ETE4_G) { regs->psw.amode64 = 1; regs->psw.amode = 1; regs->psw.AMASK = AMASK64; regs->psw.IA = ((U64)(ete[0]) << 32) | (U64)(ete[1] & 0xFFFFFFFE); } else { regs->psw.amode64 = 0; regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; regs->psw.IA = ete[1] & ETE1_EIA; } #else /*!defined(FEATURE_ESAME)*/ regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; regs->psw.IA = ete[1] & ETE1_EIA; #endif /*!defined(FEATURE_ESAME)*/ regs->psw.prob = (ete[1] & ETE1_PROB) ? 1 : 0; /* Replace the PSW key by the entry key if the K bit is set */ if (ete[4] & ETE4_K) { INVALIDATE_AIA(regs); regs->psw.pkey = (ete[4] & ETE4_EK) >> 16; } /* Replace the PSW key mask by the EKM if the M bit is set, otherwise OR the EKM into the current PSW key mask */ if (ete[4] & ETE4_M) regs->CR_LHH(3) = 0; regs->CR(3) |= (ete[3] & ETE3_EKM); /* Replace the EAX key by the EEAX if the E bit is set */ if (ete[4] & ETE4_E) { regs->CR_LHH(8) = (ete[4] & ETE4_EEAX); } /* Set the access mode according to the C bit */ regs->psw.armode = (ete[4] & ETE4_C) ? 1 : 0; /* Load the entry parameter into general register 4 */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_H(4) = ete[6]; regs->GR_L(4) = ete[7]; #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(4) = ete[2]; #endif /*!defined(FEATURE_ESAME)*/ } /* end if(stacking PC) */ #else /*!defined(FEATURE_LINKAGE_STACK)*/ ARCH_DEP(program_interrupt) (regs, PGM_PC_TRANSLATION_SPECIFICATION_EXCEPTION); #endif /*!defined(FEATURE_LINKAGE_STACK)*/ /* If new ASN is zero, perform program call to current primary */ if (pasn == 0) { /* Set SASN equal to PASN */ regs->CR_LHL(3) = regs->CR_LHL(4); /* Set SSTD equal to PSTD */ regs->CR(7) = regs->CR(1); } /* end if(PC-cp) */ else { /* Program call with space switching */ /* Set SASN and SSTD equal to current PASN and PSTD */ regs->CR_LHL(3) = regs->CR_LHL(4); regs->CR(7) = regs->CR(1); /* Set flag if either the current or new PSTD indicates a space switch event */ if ((regs->CR(1) & SSEVENT_BIT) || (ASTE_AS_DESIGNATOR(aste) & SSEVENT_BIT) ) { /* Indicate space-switch event required */ ssevent = 1; } /* Obtain new AX from the ASTE and new PASN from the ET */ regs->CR_L(4) = (aste[1] & ASTE1_AX) | pasn; /* Load the new primary STD or ASCE */ regs->CR(1) = pstd; /* Update control register 5 with the new PASTEO or LTD */ regs->CR_L(5) = ASF_ENABLED(regs) ? pasteo : ASTE_LT_DESIGNATOR(aste); #if defined(FEATURE_LINKAGE_STACK) /* For stacking PC when the S-bit in the entry table is one, set SASN and SSTD equal to new PASN and PSTD */ if ((ete[4] & ETE4_T) && (ete[4] & ETE4_S)) { regs->CR_LHL(3) = regs->CR_LHL(4); regs->CR(7) = regs->CR(1); } #endif /*defined(FEATURE_LINKAGE_STACK)*/ } /* end if(PC-ss) */ #ifdef FEATURE_TRACING /* Update trace table address if ASN tracing is active */ if (regs->CR(12) & CR12_ASNTRACE) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ #if defined(FEATURE_PER) if( EN_IC_PER_SB(regs) #if defined(FEATURE_PER2) && ( !(regs->CR(9) & CR9_BAC) || PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) ) #endif /*defined(FEATURE_PER2)*/ ) ON_IC_PER_SB(regs); #endif /*defined(FEATURE_PER)*/ /* Generate space switch event if required */ if ( ssevent || (pasn != 0 && IS_IC_PER(regs)) ) { /* [6.5.2.34] Set the translation exception address equal to the old primary ASN, with the high-order bit set if the old primary space-switch-event control bit is one */ regs->TEA = oldpasn; if (oldpstd & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; ARCH_DEP(program_interrupt) (regs, PGM_SPACE_SWITCH_EVENT); } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* 0101 PR - Program Return [E] */ /*-------------------------------------------------------------------*/ DEF_INST(program_return) { REGS newregs; /* Copy of CPU registers */ int etype; /* Entry type unstacked */ int ssevent = 0; /* 1=space switch event */ RADR alsed; /* Absolute addr of LSED of previous stack entry */ LSED *lsedp; /* -> LSED in main storage */ U32 aste[16]; /* ASN second table entry */ U32 pasteo; /* Primary ASTE origin */ U32 sasteo; /* Secondary ASTE origin */ U16 oldpasn; /* Original primary ASN */ U32 oldpstd; /* Original primary STD */ U16 pasn = 0; /* New primary ASN */ U16 sasn; /* New secondary ASN */ U16 ax; /* Authorization index */ U16 xcode; /* Exception code */ int rc; /* return code from load_psw */ E(inst, execflag, regs); SIE_MODE_XC_OPEX(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_PR)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Create a working copy of the CPU registers */ newregs = *regs; /* Save the primary ASN (CR4) and primary STD (CR1) */ oldpasn = regs->CR_LHL(4); oldpstd = regs->CR(1); /* Perform the unstacking process */ etype = ARCH_DEP(program_return_unstack) (&newregs, &alsed, &rc); /* Perform PR-cp or PR-ss if unstacked entry was a program call */ if (etype == LSED_UET_PC) { /* Extract the new primary ASN from CR4 bits 16-31 */ pasn = newregs.CR_LHL(4); #ifdef FEATURE_TRACING /* Perform tracing if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) newregs.CR(12) = ARCH_DEP(trace_pr) (&newregs, regs); #if defined(FEATURE_ESAME) else /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && regs->psw.amode64 != newregs.psw.amode64) ARCH_DEP(trace_ms) (0, newregs.psw.IA, regs); #endif /*defined(FEATURE_ESAME)*/ #endif /*FEATURE_TRACING*/ /* Perform PASN translation if new PASN not equal old PASN */ if (pasn != oldpasn) { /* Special operation exception if ASN translation control (control register 14 bit 12) is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (&newregs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Translate new primary ASN to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (pasn, &newregs, &pasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (&newregs, xcode); /* Space switch if either current PSTD or new PSTD space-switch-event control bit is set to 1 */ if ((regs->CR(1) & SSEVENT_BIT) || (ASTE_AS_DESIGNATOR(aste) & SSEVENT_BIT)) { /* Indicate space-switch event required */ ssevent = 1; } else { /* space-switch event maybe - if PER event */ ssevent = 2; } /* Obtain new PSTD (or PASCE) and AX from the ASTE */ newregs.CR(1) = ASTE_AS_DESIGNATOR(aste); newregs.CR_LHH(4) = 0; newregs.CR_L(4) |= aste[1] & ASTE1_AX; /* Load CR5 with the primary ASTE origin address */ newregs.CR_L(5) = pasteo; #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ newregs.CR(1) = ARCH_DEP(subspace_replace) (newregs.CR(1), pasteo, NULL, &newregs); #endif /*FEATURE_SUBSPACE_GROUP*/ } /* end if(pasn!=oldpasn) */ /* Extract the new secondary ASN from CR3 bits 16-31 */ sasn = newregs.CR_LHL(3); /* Set SSTD = PSTD if new SASN is equal to new PASN */ if (sasn == pasn) { newregs.CR(7) = newregs.CR(1); } else /* sasn != pasn */ { /* Special operation exception if ASN translation control (control register 14 bit 12) is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (&newregs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Translate new secondary ASN to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (sasn, &newregs, &sasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (&newregs, xcode); /* Obtain new SSTD or SASCE from secondary ASTE */ newregs.CR(7) = ASTE_AS_DESIGNATOR(aste); /* Perform SASN authorization using new AX */ ax = newregs.CR_LHH(4); if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY, &newregs)) { newregs.TEA = sasn; ARCH_DEP(program_interrupt) (&newregs, PGM_SECONDARY_AUTHORITY_EXCEPTION); } #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new SSTD */ newregs.CR(7) = ARCH_DEP(subspace_replace) (newregs.CR(7), sasteo, NULL, &newregs); #endif /*FEATURE_SUBSPACE_GROUP*/ } /* end else(sasn!=pasn) */ } /* end if(LSED_UET_PC) */ /* Update the updated CPU registers from the working copy */ memcpy(regs->gr, newregs.gr, sizeof(newregs.gr)); memcpy(regs->ar, newregs.ar, sizeof(newregs.ar)); memcpy(regs->cr, newregs.cr, sizeof(newregs.cr)); memcpy(&(regs->psw), &(newregs.psw), sizeof(newregs.psw)); INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); SET_IC_EXTERNAL_MASK(regs); SET_IC_MCK_MASK(regs); SET_IC_IO_MASK(regs); regs->psw.ilc = 2; /* Set the main storage reference and change bits */ STORAGE_KEY(alsed) |= (STORKEY_REF | STORKEY_CHANGE); /* [5.12.4.4] Clear the next entry size field of the linkage stack entry now pointed to by control register 15 */ lsedp = (LSED*)(sysblk.mainstor + alsed); lsedp->nes[0] = 0; lsedp->nes[1] = 0; #if defined(FEATURE_PER) /* Copy PER info from working copy to real copy of registers */ if (IS_IC_PER_SA(&newregs)) { ON_IC_PER_SA(regs); regs->perc = newregs.perc; } if( EN_IC_PER_SB(regs) #if defined(FEATURE_PER2) && ( !(regs->CR(9) & CR9_BAC) || PER_RANGE_CHECK(regs->psw.IA,regs->CR(10),regs->CR(11)) ) #endif /*defined(FEATURE_PER2)*/ ) ON_IC_PER_SB(regs); #endif /*defined(FEATURE_PER)*/ /* Generate space switch event if required */ if ( ssevent == 1 || (ssevent == 2 && IS_IC_PER(regs)) ) { /* [6.5.2.34] Set translation exception address equal to old primary ASN, and set high-order bit if old primary space-switch-event control bit is one */ newregs.TEA = oldpasn; if (oldpstd & SSEVENT_BIT) newregs.TEA |= TEA_SSEVENT; ARCH_DEP(program_interrupt) (&newregs, PGM_SPACE_SWITCH_EVENT); } if (rc) /* if new psw has bad format */ { regs->psw.ilc = 0; ARCH_DEP(program_interrupt) (&newregs, rc); } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); RETURN_INTCHECK(regs); } #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B228 PT - Program Transfer [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(program_transfer) { int r1, r2; /* Values of R fields */ U16 pkm; /* New program key mask */ U16 pasn; /* New primary ASN */ U16 oldpasn; /* Old primary ASN */ int amode; /* New amode */ VADR ia; /* New instruction address */ int prob; /* New problem state bit */ RADR abs; /* Absolute address */ U32 ltd; /* Linkage table designation */ U32 pasteo; /* Primary ASTE origin */ U32 aste[16]; /* ASN second table entry */ CREG pstd; /* Primary STD */ U32 oldpstd; /* Old Primary STD */ U16 ax; /* Authorization index */ U16 xcode; /* Exception code */ int ssevent = 0; /* 1=space switch event */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); INVALIDATE_AEA_ALL(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_PT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Special operation exception if DAT is off, or not in primary space mode */ if (REAL_MODE(&(regs->psw)) || !PRIMARY_SPACE_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Special operation exception if subsystem linkage control bit in CR5 is zero (when ASF is off)*/ if (!ASF_ENABLED(regs) && !(regs->CR_L(5) & LTD_SSLINK)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Save the primary ASN (CR4) and primary STD (CR1) */ oldpasn = regs->CR_LHL(4); oldpstd = regs->CR(1); /* Extract the PSW key mask from R1 register bits 0-15 */ pkm = regs->GR_LHH(r1); /* Extract the ASN from R1 register bits 16-31 */ pasn = regs->GR_LHL(r1); #ifdef FEATURE_TRACING /* Build trace entry if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_pt) (pasn, regs->GR(r2), regs); #endif /*FEATURE_TRACING*/ /* Determine instruction address, amode, and problem state */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { /* In 64-bit address mode, extract instruction address from R2 register bits 0-62, and leave address mode unchanged */ ia = regs->GR_G(r2) & 0xFFFFFFFFFFFFFFFEULL; amode = regs->psw.amode; } else #endif /*defined(FEATURE_ESAME)*/ { /* In 31- or 24-bit mode, extract new amode from R2 bit 0 */ amode = (regs->GR_L(r2) & 0x80000000) ? 1 : 0; /* Extract the instruction address from R2 bits 1-30 */ ia = regs->GR_L(r2) & 0x7FFFFFFE; } /* Extract the problem state bit from R2 register bit 31 */ prob = regs->GR_L(r2) & 0x00000001; /* [5.5.3.1] Load the linkage table designation */ if (!ASF_ENABLED(regs)) { /* Obtain the LTD from control register 5 */ ltd = regs->CR_L(5); } else { /* Obtain the primary ASTE origin from control register 5 */ pasteo = regs->CR_L(5) & CR5_PASTEO; /* Convert the PASTE origin to an absolute address */ abs = APPLY_PREFIXING (pasteo, regs->PX); /* Program check if PASTE is outside main storage */ if (abs >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch primary ASTE words 3 and 6 from absolute storage (note: the ASTE cannot cross a page boundary) */ #if !defined(FEATURE_ESAME) aste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs); #else /*defined(FEATURE_ESAME)*/ aste[6] = ARCH_DEP(fetch_fullword_absolute) (abs+24, regs); #endif /*defined(FEATURE_ESAME)*/ /* Load LTD from primary ASTE word 3 or 6 */ ltd = ASTE_LT_DESIGNATOR(aste); } /* Special operation exception if subsystem linkage control bit in linkage table designation is zero */ if ((ltd & LTD_SSLINK) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and problem bit indicates a change to supervisor state */ if (regs->psw.prob && prob == 0) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Specification exception if new amode is 24-bit and new instruction address is not a 24-bit address */ if (amode == 0 && ia > 0x00FFFFFF) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Space switch if ASN not equal to current PASN */ if ( pasn != regs->CR_LHL(4) ) { INVALIDATE_AIA(regs); /* Special operation exception if ASN translation control (control register 14 bit 12) is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Translate ASN and generate program check if AFX- or ASX-translation exception condition */ xcode = ARCH_DEP(translate_asn) (pasn, regs, &pasteo, aste); if (xcode != 0) ARCH_DEP(program_interrupt) (regs, xcode); /* Perform primary address space authorization using current authorization index */ ax = regs->CR_LHH(4); if (ARCH_DEP(authorize_asn) (ax, aste, ATE_PRIMARY, regs)) { regs->TEA = pasn; ARCH_DEP(program_interrupt) (regs, PGM_PRIMARY_AUTHORITY_EXCEPTION); } /* Obtain new primary STD or ASCE from the ASTE */ pstd = ASTE_AS_DESIGNATOR(aste); #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, NULL, regs); #endif /*FEATURE_SUBSPACE_GROUP*/ /* Space switch if either current PSTD or new PSTD space-switch-event control bit is set to 1 */ if ((regs->CR(1) & SSEVENT_BIT) || (pstd & SSEVENT_BIT)) { /* Indicate space-switch event required */ ssevent = 1; } else { ssevent = 2; /* maybe, if PER is pending */ } /* Load new primary STD or ASCE into control register 1 */ regs->CR(1) = pstd; /* Load new AX and PASN into control register 4 */ regs->CR_L(4) = (aste[1] & ASTE1_AX) | pasn; /* Load new PASTEO or LTD into control register 5 */ regs->CR_L(5) = ASF_ENABLED(regs) ? pasteo : ASTE_LT_DESIGNATOR(aste); } /* end if(PT-ss) */ else { /* For PT-cp use current primary STD or ASCE */ pstd = regs->CR(1); } #ifdef FEATURE_TRACING /* Update trace table address if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ #if defined(FEATURE_PER) if( EN_IC_PER_SB(regs) #if defined(FEATURE_PER2) && ( !(regs->CR(9) & CR9_BAC) || PER_RANGE_CHECK(ia,regs->CR(10),regs->CR(11)) ) #endif /*defined(FEATURE_PER2)*/ ) ON_IC_PER_SB(regs); #endif /*defined(FEATURE_PER)*/ /* Replace PSW amode, instruction address, and problem state bit */ regs->psw.amode = amode; regs->psw.IA = ia; regs->psw.prob = prob; regs->psw.AMASK = #if defined(FEATURE_ESAME) regs->psw.amode64 ? AMASK64 : #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode ? AMASK31 : AMASK24; /* AND control register 3 bits 0-15 with the supplied PKM value and replace the SASN in CR3 bits 16-31 with new PASN */ regs->CR_LHH(3) &= pkm; regs->CR_LHL(3) = pasn; /* Set secondary STD or ASCE equal to new primary STD or ASCE */ regs->CR(7) = pstd; /* Generate space switch event if required */ if ( ssevent == 1 || (ssevent == 2 && IS_IC_PER(regs)) ) { /* [6.5.2.34] Set the translation exception address equal to the old primary ASN, with the high-order bit set if the old primary space-switch-event control bit is one */ regs->TEA = oldpasn; if (oldpstd & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; ARCH_DEP(program_interrupt) (regs, PGM_SPACE_SWITCH_EVENT); } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* B248 PALB - Purge ALB [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(purge_accesslist_lookaside_buffer) { int r1, r2; /* Register values (unused) */ RRE(inst, execflag, regs, r1, r2); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* This instruction is executed as a no-operation in XC mode */ if(regs->sie_state && (regs->siebk->mx & SIE_MX_XC)) return; #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_PXLB)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Purge the ART lookaside buffer for this CPU */ ARCH_DEP(purge_alb) (regs); } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* B20D PTLB - Purge TLB [S] */ /*-------------------------------------------------------------------*/ DEF_INST(purge_translation_lookaside_buffer) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, execflag, regs, b2, effective_addr2); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* This instruction is executed as a no-operation in XC mode */ if(regs->sie_state && (regs->siebk->mx & SIE_MX_XC)) return; #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_PXLB)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Purge the translation lookaside buffer for this CPU */ ARCH_DEP(purge_tlb) (regs); } #if defined(FEATURE_BASIC_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B213 RRB - Reset Reference Bit [S] */ /*-------------------------------------------------------------------*/ DEF_INST(reset_reference_bit) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RADR n; /* Absolute storage addr */ BYTE storkey; /* Storage key */ S(inst, execflag, regs, b2, effective_addr2); #if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE) if( #if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS) regs->sie_state && #endif !(regs->CR(0) & CR0_STORKEY_4K) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif PRIV_CHECK(regs); /* Load 2K block real address from operand address */ n = effective_addr2 & 0x00FFF800; /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state) { if(regs->siebk->ic[2] & SIE_IC2_RRBE) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n); #else storkey = STORAGE_KEY1(n) | STORAGE_KEY2(n); #endif /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= ~(STORKEY_REF); #else STORAGE_KEY1(n) &= ~(STORKEY_REF); STORAGE_KEY2(n) &= ~(STORKEY_REF); #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { BYTE rcpkey, realkey; RADR ra; RADR rcpa; U16 xcode; int private, protect, stid; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private, &protect, &stid)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX); /* The reference and change byte is located directly beyond the page table and is located at offset 1 in the entry. S/370 mode cannot be emulated in ESAME mode, so no provision is made for ESAME mode tables */ rcpa += 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = sysblk.mainstor[rcpa]; STORAGE_KEY(rcpa) |= STORKEY_REF; if (!SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &ra, &xcode, &private, &protect, &stid)) { ra = APPLY_PREFIXING(ra, regs->hostregs->PX); #if !defined(_FEATURE_2K_STORAGE_KEYS) realkey = STORAGE_KEY(ra) #else realkey = (STORAGE_KEY1(ra) | STORAGE_KEY2(ra)) #endif & (STORKEY_REF | STORKEY_CHANGE); /* Reset reference and change bits in storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(ra) &= ~(STORKEY_REF | STORKEY_CHANGE); #else STORAGE_KEY1(ra) &= ~(STORKEY_REF | STORKEY_CHANGE); STORAGE_KEY2(ra) &= ~(STORKEY_REF | STORKEY_CHANGE); #endif } else realkey = 0; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = realkey | (rcpkey & (STORKEY_REF | STORKEY_CHANGE)); /* or with host set */ rcpkey |= realkey << 4; /* Put storage key in guest set */ rcpkey |= storkey; /* reset the reference bit */ rcpkey &= ~(STORKEY_REF); sysblk.mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE); } } else /* regs->sie_perf */ { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n); #else storkey = STORAGE_KEY1(n) | STORAGE_KEY2(n); #endif /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= ~(STORKEY_REF); #else STORAGE_KEY1(n) &= ~(STORKEY_REF); STORAGE_KEY2(n) &= ~(STORKEY_REF); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n); #else storkey = STORAGE_KEY1(n) | STORAGE_KEY2(n); #endif /* Reset the reference bit in the storage key */ #if defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= ~(STORKEY_REF); #else STORAGE_KEY1(n) &= ~(STORKEY_REF); STORAGE_KEY2(n) &= ~(STORKEY_REF); #endif } /* Set the condition code according to the original state of the reference and change bits in the storage key */ regs->psw.cc = ((storkey & STORKEY_REF) ? 2 : 0) | ((storkey & STORKEY_CHANGE) ? 1 : 0); } #endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/ #if defined(FEATURE_EXTENDED_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B22A RRBE - Reset Reference Bit Extended [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(reset_reference_bit_extended) { int r1, r2; /* Register values */ RADR n; /* Abs frame addr stor key */ BYTE storkey; /* Storage key */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); /* Load 4K block address from R2 register */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state) { if(regs->siebk->ic[2] & SIE_IC2_RRBE) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n); #else storkey = STORAGE_KEY1(n) | (STORAGE_KEY2(n) & (STORKEY_REF|STORKEY_CHANGE)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= ~(STORKEY_REF); #else STORAGE_KEY1(n) &= ~(STORKEY_REF); STORAGE_KEY2(n) &= ~(STORKEY_REF); #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { BYTE rcpkey, realkey; RADR ra; RADR rcpa; U16 xcode; int private, protect, stid; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private, &protect, &stid)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(regs->siebk->mx & SIE_MX_XC) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = sysblk.mainstor[rcpa]; STORAGE_KEY(rcpa) |= STORKEY_REF; if (!SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &ra, &xcode, &private, &protect, &stid)) { ra = APPLY_PREFIXING(ra, regs->hostregs->PX); #if !defined(_FEATURE_2K_STORAGE_KEYS) realkey = STORAGE_KEY(ra) & (STORKEY_REF | STORKEY_CHANGE); #else realkey = (STORAGE_KEY1(ra) | STORAGE_KEY2(ra)) & (STORKEY_REF | STORKEY_CHANGE); #endif /* Reset the reference and change bits in the real machine storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(ra) &= ~(STORKEY_REF | STORKEY_CHANGE); #else STORAGE_KEY1(ra) &= ~(STORKEY_REF | STORKEY_CHANGE); STORAGE_KEY2(ra) &= ~(STORKEY_REF | STORKEY_CHANGE); #endif } else realkey = 0; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = realkey | (rcpkey & (STORKEY_REF | STORKEY_CHANGE)); /* or with host set */ rcpkey |= realkey << 4; /* Put storage key in guest set */ rcpkey |= storkey; /* reset the reference bit */ rcpkey &= ~(STORKEY_REF); sysblk.mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE); } } else { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n); #else storkey = STORAGE_KEY1(n) | (STORAGE_KEY2(n) & (STORKEY_REF|STORKEY_CHANGE)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= ~(STORKEY_REF); #else STORAGE_KEY1(n) &= ~(STORKEY_REF); STORAGE_KEY2(n) &= ~(STORKEY_REF); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n); #else storkey = STORAGE_KEY1(n) | (STORAGE_KEY2(n) & (STORKEY_REF|STORKEY_CHANGE)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= ~(STORKEY_REF); #else STORAGE_KEY1(n) &= ~(STORKEY_REF); STORAGE_KEY2(n) &= ~(STORKEY_REF); #endif } /* Set the condition code according to the original state of the reference and change bits in the storage key */ regs->psw.cc = ((storkey & STORKEY_REF) ? 2 : 0) | ((storkey & STORKEY_CHANGE) ? 1 : 0); } /* end DEF_INST(reset_reference_bit_extended) */ #endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B219 SAC - Set Address Space Control [S] */ /* B279 SACF - Set Address Space Control Fast [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_address_space_control_x) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE mode; /* New addressing mode */ BYTE oldmode; /* Current addressing mode */ int ssevent = 0; /* 1=space switch event */ S(inst, execflag, regs, b2, effective_addr2); INVALIDATE_AEA_ALL(regs); if(inst[1] == 0x19) { /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* Isolate bits 20-23 of effective address */ mode = (effective_addr2 & 0x00000F00) >> 8; /* Special operation exception if DAT is off or secondary-space control bit is zero */ if ((REAL_MODE(&(regs->psw)) || (regs->CR(0) & CR0_SEC_SPACE) == 0) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) && !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC)) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if setting home-space mode while in problem state */ if (mode == 3 && regs->psw.prob) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Special operation exception if setting AR mode and address-space function control bit is zero */ if (mode == 2 && !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Specification exception if mode is invalid */ if (mode > 3 #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Secondary and Home space mode are not supported in XC mode */ || (regs->sie_state && (regs->siebk->mx & SIE_MX_XC) && (mode == 1 || mode == 3) ) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Save the current address-space control bits */ oldmode = (regs->psw.armode << 1) | (regs->psw.space); /* Reset the address-space control bits in the PSW */ regs->psw.space = mode & 1; regs->psw.armode = mode >> 1; INVALIDATE_AIA(regs); /* If switching into or out of home-space mode, and also: primary space-switch-event control bit is set; or home space-switch-event control bit is set; or PER event is to be indicated then indicate a space-switch-event */ if (((oldmode != 3 && mode == 3) || (oldmode == 3 && mode != 3)) && (regs->CR(1) & SSEVENT_BIT || regs->CR(13) & SSEVENT_BIT || OPEN_IC_PERINT(regs) )) { /* Indicate space-switch event required */ ssevent = 1; /* [6.5.2.34] Set the translation exception address */ if (mode == 3) { /* When switching into home-space mode, set the translation exception address equal to the primary ASN, with the high-order bit set equal to the value of the primary space-switch-event control bit */ regs->TEA = regs->CR_LHL(4); if (regs->CR(1) & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; } else { /* When switching out of home-space mode, set the translation exception address equal to zero, with the high-order bit set equal to the value of the home space-switch-event control bit */ regs->TEA = 0; if (regs->CR(13) & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; } } /* Generate a space-switch-event if indicated */ if (ssevent) ARCH_DEP(program_interrupt) (regs, PGM_SPACE_SWITCH_EVENT); if(inst[1] == 0x19) { /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* B204 SCK - Set Clock [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_clock) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Clock value */ int cpu; S(inst, execflag, regs, b2, effective_addr2); SIE_MODE_XC_OPEX(regs); PRIV_CHECK(regs); SIE_INTERCEPT(regs); DW_CHECK(effective_addr2, regs); /* Fetch new TOD clock value from operand address */ dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs); /* Obtain the TOD clock update lock */ obtain_lock (&sysblk.todlock); /* Compute the new TOD clock offset in hercules clock units */ sysblk.todoffset = (dreg >> 8) - sysblk.todclk; /* Update the TOD clock of all CPU's in the configuration as we simulate 1 shared TOD clock, and do not support the TOD clock sync check */ for(cpu = 0; cpu < MAX_CPU_ENGINES; cpu++) sysblk.regs[cpu].todoffset = sysblk.todoffset; /* Release the TOD clock update lock */ release_lock (&sysblk.todlock); // /*debug*/logmsg("Set TOD clock=%16.16llX\n", dreg); /* Return condition code zero */ regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* B206 SCKC - Set Clock Comparator [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_clock_comparator) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Clock value */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SCKC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Fetch clock comparator value from operand location */ dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ) & 0xFFFFFFFFFFFFF000ULL; // /*debug*/logmsg("Set clock comparator=%16.16llX\n", dreg); /* Obtain the TOD clock update lock */ obtain_lock (&sysblk.todlock); /* Update the clock comparator and set epoch to zero */ regs->clkc = dreg >> 8; /* reset the clock comparator pending flag according to the setting of the tod clock */ update_TOD_clock(); /* Release the TOD clock update lock */ release_lock (&sysblk.todlock); RETURN_INTCHECK(regs); } #if defined(FEATURE_EXTENDED_TOD_CLOCK) /*-------------------------------------------------------------------*/ /* 0107 SCKPF - Set Clock Programmable Field [E] */ /*-------------------------------------------------------------------*/ DEF_INST(set_clock_programmable_field) { E(inst, execflag, regs); PRIV_CHECK(regs); /* Program check if register 0 bits 0-15 are not zeroes */ if ( regs->GR_LHH(0) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Set TOD programmable register from register 0 */ regs->todpr = regs->GR_LHL(0); } #endif /*defined(FEATURE_EXTENDED_TOD_CLOCK)*/ /*-------------------------------------------------------------------*/ /* B208 SPT - Set CPU Timer [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_cpu_timer) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Timer value */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SPT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Fetch the CPU timer value from operand location */ dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ) & 0xFFFFFFFFFFFFF000ULL; /* Obtain the TOD clock update lock */ obtain_lock (&sysblk.todlock); /* Update the CPU timer */ regs->ptimer = dreg; /* reset the cpu timer pending flag according to its value */ update_TOD_clock(); /* Release the TOD clock update lock */ release_lock (&sysblk.todlock); // /*debug*/logmsg("Set CPU timer=%16.16llX\n", dreg); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B210 SPX - Set Prefix [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_prefix) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RADR n; /* Prefix value */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); FW_CHECK(effective_addr2, regs); /* Perform serialization before fetching the operand */ PERFORM_SERIALIZATION (regs); /* Load new prefix value from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Isolate bits 1-19 for ESA/390 or 1-18 for ESAME of new prefix value */ n &= PX_MASK; /* Program check if prefix is invalid absolute address */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Load new value into prefix register */ regs->PX = n; /* Invalidate the ALB and TLB */ ARCH_DEP(purge_tlb) (regs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (regs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /* Perform serialization after completing the operation */ PERFORM_SERIALIZATION (regs); } /*-------------------------------------------------------------------*/ /* B20A SPKA - Set PSW Key from Address [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_psw_key_from_address) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int n; /* Storage key workarea */ S(inst, execflag, regs, b2, effective_addr2); /* Isolate the key from bits 24-27 of effective address */ n = effective_addr2 & 0x000000F0; /* Privileged operation exception if in problem state and the corresponding PSW key mask bit is zero */ if ( regs->psw.prob && ((regs->CR(3) << (n >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); /* Set PSW key */ regs->psw.pkey = n; } #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B225 SSAR - Set Secondary ASN [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(set_secondary_asn) { int r1, r2; /* Register numbers */ U16 sasn; /* New Secondary ASN */ RADR sstd; /* Secondary STD */ U32 sasteo; /* Secondary ASTE origin */ U32 aste[16]; /* ASN second table entry */ U16 xcode; /* Exception code */ U16 ax; /* Authorization index */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ RRE(inst, execflag, regs, r1, r2); SIE_MODE_XC_OPEX(regs); INVALIDATE_AEA_ALL(regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Special operation exception if ASN translation control (bit 12 of control register 14) is zero or DAT is off */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0 || REAL_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load the new ASN from R1 register bits 16-31 */ sasn = regs->GR_LHL(r1); #ifdef FEATURE_TRACING /* Form trace entry if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_ssar) (sasn, regs); #endif /*FEATURE_TRACING*/ /* Test for SSAR to current primary */ if ( sasn == regs->CR_LHL(4) ) { /* Set new secondary STD equal to primary STD */ sstd = regs->CR(1); } /* end if(SSAR-cp) */ else { /* SSAR with space-switch */ /* Perform ASN translation to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (sasn, regs, &sasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (regs, xcode); /* Perform ASN authorization using current AX */ ax = regs->CR_LHH(4); if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY, regs)) { regs->TEA = sasn; ARCH_DEP(program_interrupt) (regs, PGM_SECONDARY_AUTHORITY_EXCEPTION); } /* Load new secondary STD or ASCE from the ASTE */ sstd = ASTE_AS_DESIGNATOR(aste); #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new SSTD */ sstd = ARCH_DEP(subspace_replace) (sstd, sasteo, NULL, regs); #endif /*FEATURE_SUBSPACE_GROUP*/ } /* end if(SSAR-ss) */ #ifdef FEATURE_TRACING /* Update trace table address if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ /* Load the new secondary ASN into control register 3 */ regs->CR_LHL(3) = sasn; /* Load the new secondary STD into control register 7 */ regs->CR(7) = sstd; /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_BASIC_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* 08 SSK - Set Storage Key [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(set_storage_key) { int r1, r2; /* Values of R fields */ RADR n; /* Absolute storage addr */ RR(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); #if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE) if( #if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS) regs->sie_state && #endif !(regs->CR(0) & CR0_STORKEY_4K) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); /* Program check if R2 bits 28-31 are not zeroes */ if ( regs->GR_L(r2) & 0x0000000F ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Load 2K block address from R2 register */ n = regs->GR_L(r2) & 0x00FFF800; /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state) { if(regs->siebk->ic[2] & SIE_IC2_SSKE) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { U16 xcode; int private, protect, stid, sr; BYTE realkey, rcpkey; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private, &protect, &stid)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX); /* The reference and change byte is located directly beyond the page table and is located at offset 1 in the entry. S/370 mode cannot be emulated in ESAME mode, so no provision is made for ESAME mode tables */ rcpa += 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* guest absolute to host real */ sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private, &protect, &stid); if(sr #if defined(_FEATURE_STORAGE_KEY_ASSIST) && !(regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(sr) realkey = 0; else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(n, regs->hostregs->PX); realkey = #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) #else (STORAGE_KEY1(n) | STORAGE_KEY2(n)) #endif & (STORKEY_REF | STORKEY_CHANGE); } /* fetch the RCP key */ rcpkey = sysblk.mainstor[rcpa]; STORAGE_KEY(rcpa) |= STORKEY_REF; /* or with host set */ rcpkey |= realkey << 4; /* or new settings with guest set */ rcpkey &= ~(STORKEY_REF | STORKEY_CHANGE); rcpkey |= regs->GR_L(r1) & (STORKEY_REF | STORKEY_CHANGE); sysblk.mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE); #if defined(_FEATURE_STORAGE_KEY_ASSIST) /* Insert key in new storage key */ if(regs->siebk->rcpo[0] & SIE_RCPO0_SKA) sysblk.mainstor[rcpa-1] = regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); if(!sr) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= STORKEY_BADFRM; STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); #else STORAGE_KEY1(n) &= STORKEY_BADFRM; STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); STORAGE_KEY2(n) &= STORKEY_BADFRM; STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); #endif } } } else { /* Update the storage key from R1 register bits 24-30 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= STORKEY_BADFRM; STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n) &= STORKEY_BADFRM; STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); STORAGE_KEY2(n) &= STORKEY_BADFRM; STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { /* Update the storage key from R1 register bits 24-30 */ #if defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= STORKEY_BADFRM; STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n) &= STORKEY_BADFRM; STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); STORAGE_KEY2(n) &= STORKEY_BADFRM; STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #endif } // /*debug*/logmsg("SSK storage block %8.8X key %2.2X\n", // /*debug*/ regs->GR_L(r2), regs->GR_LHLCL(r1) & 0xFE); } #endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/ #if defined(FEATURE_EXTENDED_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B22B SSKE - Set Storage Key extended [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(set_storage_key_extended) { int r1, r2; /* Register numbers */ RADR n; /* Abs frame addr stor key */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); /* Load 4K block address from R2 register */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state) { if(regs->siebk->ic[2] & SIE_IC2_SSKE) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && (regs->siebk->rcpo[2] & SIE_RCPO2_RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { U16 xcode; int private, protect, stid, sr; BYTE realkey, rcpkey; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE, &rcpa, &xcode, &private, &protect, &stid)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (rcpa, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(regs->siebk->mx & SIE_MX_XC) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* guest absolute to host real */ sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &n, &xcode, &private, &protect, &stid); if(sr #if defined(_FEATURE_STORAGE_KEY_ASSIST) && !((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(sr) realkey = 0; else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(n, regs->hostregs->PX); realkey = #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) #else (STORAGE_KEY1(n) | STORAGE_KEY2(n)) #endif & (STORKEY_REF | STORKEY_CHANGE); } /* fetch the RCP key */ rcpkey = sysblk.mainstor[rcpa]; STORAGE_KEY(rcpa) |= STORKEY_REF; /* or with host set */ rcpkey |= realkey << 4; /* insert new settings of the guest set */ rcpkey &= ~(STORKEY_REF | STORKEY_CHANGE); rcpkey |= regs->GR_LHLCL(r1) & (STORKEY_REF | STORKEY_CHANGE); sysblk.mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa) |= (STORKEY_REF|STORKEY_CHANGE); #if defined(_FEATURE_STORAGE_KEY_ASSIST) /* Insert key in new storage key */ if((regs->siebk->rcpo[0] & SIE_RCPO0_SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) sysblk.mainstor[rcpa-1] = regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); if(!sr) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= STORKEY_BADFRM; STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); #else STORAGE_KEY1(n) &= STORKEY_BADFRM; STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); STORAGE_KEY2(n) &= STORKEY_BADFRM; STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); #endif } } } else { /* Update the storage key from R1 register bits 24-30 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= STORKEY_BADFRM; STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n) &= STORKEY_BADFRM; STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); STORAGE_KEY2(n) &= STORKEY_BADFRM; STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { /* Update the storage key from R1 register bits 24-30 */ #if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n) &= STORKEY_BADFRM; STORAGE_KEY(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n) &= STORKEY_BADFRM; STORAGE_KEY1(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); STORAGE_KEY2(n) &= STORKEY_BADFRM; STORAGE_KEY2(n) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #endif } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } #endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ /*-------------------------------------------------------------------*/ /* 80 SSM - Set System Mask [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_system_mask) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ #if defined(OPTION_REDUCED_INVAL) int realmode; int space; int armode; #endif S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(OPTION_REDUCED_INVAL) realmode = REAL_MODE(®s->psw); armode = (regs->psw.armode == 1); space = (regs->psw.space == 1); #endif /* Special operation exception if SSM-suppression is active */ if ( (regs->CR(0) & CR0_SSM_SUPP) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* SSM-suppression is ignored in XC mode */ && !(regs->sie_state && (regs->siebk->mx & SIE_MX_XC)) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_SSM)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Load new system mask value from operand address */ regs->psw.sysmask = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* DAT must be off in XC mode */ if(regs->sie_state && (regs->siebk->mx & SIE_MX_XC) && (regs->psw.sysmask & PSW_DATMODE) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* For ECMODE, bits 0 and 2-4 of system mask must be zero */ if ( #if defined(FEATURE_BCMODE) regs->psw.ecmode && #endif /*defined(FEATURE_BCMODE)*/ (regs->psw.sysmask & 0xB8) != 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); SET_IC_EXTERNAL_MASK(regs); SET_IC_MCK_MASK(regs); SET_IC_IO_MASK(regs); SET_IC_PER_MASK(regs); INVALIDATE_AIA(regs); #if defined(OPTION_REDUCED_INVAL) if ((realmode != REAL_MODE(®s->psw)) || (armode != (regs->psw.armode == 1)) || (space != (regs->psw.space == 1)) #if defined(FEATURE_PER) || PER_MODE(regs) #endif /*defined(FEATURE_PER)*/ ) INVALIDATE_AEA_ALL(regs); #else INVALIDATE_AEA_ALL(regs); #endif RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* AE SIGP - Signal Processor [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(signal_procesor) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ REGS *tregs; /* -> Target CPU registers */ GREG parm; /* Signal parameter */ GREG status = 0; /* Signal status */ RADR abs; /* Absolute address */ U16 cpad; /* Target CPU address */ BYTE order; /* SIGP order code */ #if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS) int cpu; /* cpu number */ int set_arch = 0; /* Need to switch mode */ #endif /*defined(_900) || defined(FEATURE_ESAME)*/ static char *ordername[] = { "Unassigned", /* SIGP_SENSE */ "Sense", /* SIGP_EXTCALL */ "External call", /* SIGP_EMERGENCY */ "Emergency signal", /* SIGP_START */ "Start", /* SIGP_STOP */ "Stop", /* SIGP_RESTART */ "Restart", /* SIGP_IPR */ "Initial program reset", /* SIGP_PR */ "Program reset", /* SIGP_STOPSTORE */ "Stop and store status", /* SIGP_IMPL */ "Initial microprogram load", /* SIGP_INITRESET */ "Initial CPU reset", /* SIGP_RESET */ "CPU reset", /* SIGP_SETPREFIX */ "Set prefix", /* SIGP_STORE */ "Store status", /* 0x0F */ "Unassigned", /* 0x10 */ "Unassigned", /* SIGP_STOREX */ "Store extended status at address", /* SIGP_SETARCH */ "Set Architecture Mode" }; RS(inst, execflag, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Load the order code from operand address bits 24-31 */ order = effective_addr2 & 0xFF; /* Load the target CPU address from R3 bits 16-31 */ cpad = (order != SIGP_SETARCH) ? regs->GR_LHL(r3) : regs->cpuad; /* Load the parameter from R1 (if R1 odd), or R1+1 (if even) */ parm = (r1 & 1) ? regs->GR_L(r1) : regs->GR_L(r1+1); /* Return condition code 3 if target CPU does not exist */ #ifdef _FEATURE_CPU_RECONFIG if (cpad >= MAX_CPU_ENGINES) #else /*!_FEATURE_CPU_RECONFIG*/ if (cpad >= sysblk.numcpu) #endif /*!_FEATURE_CPU_RECONFIG*/ { regs->psw.cc = 3; return; } /* Point to the target CPU */ tregs = sysblk.regs + cpad; /* Trace SIGP unless Sense, External Call, Emergency Signal, or the target CPU is configured offline */ if (order > LOG_SIGPORDER || !tregs->cpuonline) #if !defined(FEATURE_ESAME) logmsg ("CPU%4.4X: SIGP CPU%4.4X %s PARM %8.8X\n", regs->cpuad, cpad, order > MAX_SIGPORDER ? ordername[0] : ordername[order], parm); #else /*defined(FEATURE_ESAME)*/ logmsg ("CPU%4.4X: SIGP CPU%4.4X %s PARM %16.16llX\n", regs->cpuad, cpad, order > MAX_SIGPORDER ? ordername[0] : ordername[order], (long long)parm); #endif /*defined(FEATURE_ESAME)*/ /* [4.9.2.1] Claim the use of the CPU signaling and response facility, and return condition code 2 if the facility is busy. The sigplock is held while the facility is in use by any CPU. */ if(try_obtain_lock (&sysblk.sigplock)) { regs->psw.cc = 2; return; } /* Obtain the interrupt lock */ obtain_lock(&sysblk.intlock); /* If the cpu is not part of the configuration then return cc3 Initial CPU reset may IML a processor that is currently not part of the configuration, ie configure the cpu implicitly online */ if (order != SIGP_INITRESET #if defined(FEATURE_S370_CHANNEL) && order != SIGP_IMPL #endif /*defined(FEATURE_S370_CHANNEL)*/ && !tregs->cpuonline) { release_lock(&sysblk.sigplock); release_lock(&sysblk.intlock); regs->psw.cc = 3; return; } /* Except for the reset orders, return condition code 2 if the target CPU is executing a previous start, stop, restart, stop and store status, set prefix, or store status order */ if ((order != SIGP_RESET #if defined(FEATURE_S370_CHANNEL) && order != SIGP_IMPL && order != SIGP_IPR #endif /*defined(FEATURE_S370_CHANNEL)*/ && order != SIGP_INITRESET) && (tregs->cpustate == CPUSTATE_STOPPING || IS_IC_RESTART(tregs))) { release_lock(&sysblk.sigplock); release_lock(&sysblk.intlock); regs->psw.cc = 2; return; } /* If the CPU thread is still starting, ie CPU is still performing the IML process then relect an operator intervening status to the caller */ if(tregs->cpustate == CPUSTATE_STARTING) status |= SIGP_STATUS_OPERATOR_INTERVENING; else /* Process signal according to order code */ switch (order) { case SIGP_SENSE: /* Set status bit 24 if external call interrupt pending */ if (IS_IC_EXTCALL(tregs)) status |= SIGP_STATUS_EXTERNAL_CALL_PENDING; /* Set status bit 25 if target CPU is stopped */ if (tregs->cpustate != CPUSTATE_STARTED) status |= SIGP_STATUS_STOPPED; /* Test for checkstop state */ if(tregs->checkstop) status |= SIGP_STATUS_CHECK_STOP; break; case SIGP_EXTCALL: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Exit with status bit 24 set if a previous external call interrupt is still pending in the target CPU */ if (IS_IC_EXTCALL(tregs)) { status |= SIGP_STATUS_EXTERNAL_CALL_PENDING; break; } /* Raise an external call interrupt pending condition */ ON_IC_EXTCALL(tregs); tregs->extccpu = regs->cpuad; break; case SIGP_EMERGENCY: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Raise an emergency signal interrupt pending condition */ ON_IC_EMERSIG(tregs); tregs->emercpu[regs->cpuad] = 1; break; case SIGP_START: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Restart the target CPU if it is in the stopped state */ tregs->cpustate = CPUSTATE_STARTED; OFF_IC_CPU_NOT_STARTED(tregs); break; case SIGP_STOP: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Put the the target CPU into the stopping state */ tregs->cpustate = CPUSTATE_STOPPING; ON_IC_CPU_NOT_STARTED(tregs); break; case SIGP_RESTART: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Make restart interrupt pending in the target CPU */ ON_IC_RESTART(tregs); /* Set cpustate to stopping. If the restart is successful, then the cpustate will be set to started in cpu.c */ if(tregs->cpustate == CPUSTATE_STOPPED) tregs->cpustate = CPUSTATE_STOPPING; break; case SIGP_STOPSTORE: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Indicate store status is required when stopped */ ON_IC_STORSTAT(tregs); /* Put the the target CPU into the stopping state */ tregs->cpustate = CPUSTATE_STOPPING; ON_IC_CPU_NOT_STARTED(tregs); break; #if defined(FEATURE_S370_CHANNEL) case SIGP_IMPL: case SIGP_IPR: channelset_reset(tregs); /* fallthrough*/ #endif /* defined(FEATURE_S370_CHANNEL) */ case SIGP_INITRESET: if(tregs->cpuonline) { /* Signal initial CPU reset function */ tregs->sigpireset = 1; tregs->cpustate = CPUSTATE_STOPPING; ON_IC_CPU_NOT_STARTED(tregs); } else configure_cpu(tregs); break; #if defined(FEATURE_S370_CHANNEL) case SIGP_PR: channelset_reset(tregs); /* fallthrough*/ #endif /* defined(FEATURE_S370_CHANNEL) */ case SIGP_RESET: /* Signal CPU reset function */ tregs->sigpreset = 1; tregs->cpustate = CPUSTATE_STOPPING; ON_IC_CPU_NOT_STARTED(tregs); break; case SIGP_SETPREFIX: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Exit with operator intervening if the status is stopping, such that a retry can be attempted */ if(tregs->cpustate == CPUSTATE_STOPPING) { status |= SIGP_STATUS_OPERATOR_INTERVENING; break; } /* Exit with status bit 22 set if CPU is not stopped */ if (tregs->cpustate != CPUSTATE_STOPPED) { status |= SIGP_STATUS_INCORRECT_STATE; break; } /* Obtain new prefix from parameter register bits 1-19 or bits 1-18 in ESAME mode */ abs = parm & PX_MASK; /* Exit with status bit 23 set if new prefix is invalid */ if (abs >= regs->mainsize) { status |= SIGP_STATUS_INVALID_PARAMETER; break; } /* Load new value into prefix register of target CPU */ tregs->PX = abs; /* Invalidate the ALB and TLB of the target CPU */ ARCH_DEP(purge_tlb) (tregs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (tregs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /* Perform serialization and checkpoint-sync on target CPU */ // perform_serialization (tregs); // perform_chkpt_sync (tregs); break; case SIGP_STORE: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Exit with operator intervening if the status is stopping, such that a retry can be attempted */ if(tregs->cpustate == CPUSTATE_STOPPING) { status |= SIGP_STATUS_OPERATOR_INTERVENING; break; } /* Exit with status bit 22 set if CPU is not stopped */ if (tregs->cpustate != CPUSTATE_STOPPED) { status |= SIGP_STATUS_INCORRECT_STATE; break; } /* Obtain status address from parameter register bits 1-22 */ abs = parm & 0x7FFFFE00; /* Exit with status bit 23 set if status address invalid */ if (abs >= regs->mainsize) { status |= SIGP_STATUS_INVALID_PARAMETER; break; } /* Store status at specified main storage address */ ARCH_DEP(store_status) (tregs, abs); /* Perform serialization and checkpoint-sync on target CPU */ // perform_serialization (tregs); // perform_chkpt_sync (tregs); break; case SIGP_STOREX: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /*INCOMPLETE*/ break; #if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS) case SIGP_SETARCH: /* CPU must have ESAME support */ if(!sysblk.arch_z900) status = SIGP_STATUS_INVALID_ORDER; PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); #ifdef _FEATURE_CPU_RECONFIG for (cpu = 0; cpu < MAX_CPU_ENGINES; cpu++) #else /*!_FEATURE_CPU_RECONFIG*/ for (cpu = 0; cpu < sysblk.numcpu; cpu++) #endif /*!_FEATURE_CPU_RECONFIG*/ if(sysblk.regs[cpu].cpuonline && sysblk.regs[cpu].cpustate != CPUSTATE_STOPPED && sysblk.regs[cpu].cpuad != regs->cpuad) status |= SIGP_STATUS_INCORRECT_STATE; if(!status) switch(parm & 0xFF) { case 0: if(sysblk.arch_mode == ARCH_390) status = SIGP_STATUS_INVALID_ORDER; sysblk.arch_mode = ARCH_390; regs->psw.notesame = 1; regs->PX_L &= 0x7FFFE000; set_arch = 1; break; case 1: if(sysblk.arch_mode == ARCH_900) status = SIGP_STATUS_INVALID_ORDER; sysblk.arch_mode = ARCH_900; regs->psw.notesame = 0; regs->psw.IA_H = 0; regs->PX_G &= 0x7FFFE000; set_arch = 1; break; #if defined(FEATURE_HERCULES_DIAGCALLS) case 37: if(sysblk.arch_mode == ARCH_370) status = SIGP_STATUS_INVALID_ORDER; sysblk.arch_mode = ARCH_370; set_arch = 1; break; #endif /*defined(FEATURE_HERCULES_DIAGCALLS)*/ default: status |= SIGP_STATUS_INVALID_PARAMETER; } #if defined(OPTION_FISHIO) ios_arch_mode = sysblk.arch_mode; #endif // defined(OPTION_FISHIO) /* Invalidate the ALB and TLB */ ARCH_DEP(purge_tlb) (regs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (tregs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); break; #endif /*defined(_900) || defined(FEATURE_ESAME)*/ default: status = SIGP_STATUS_INVALID_ORDER; } /* end switch(order) */ /* Release the use of the signalling and response facility */ release_lock(&sysblk.sigplock); /* Wake up the target CPU */ WAKEUP_CPU (tregs->cpuad); /* Release the interrupt lock */ release_lock (&sysblk.intlock); /* If status is non-zero, load the status word into the R1 register and return condition code 1 */ if (status != 0) { regs->GR_L(r1) = status; regs->psw.cc = 1; } else regs->psw.cc = 0; /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); #if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS) if(set_arch) longjmp(regs->archjmp, 0); #endif /*defined(_900) || defined(FEATURE_ESAME)*/ RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B207 STCKC - Store Clock Comparator [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_clock_comparator) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Clock value */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SCKC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Obtain the TOD clock update lock */ obtain_lock (&sysblk.todlock); /* Save clock comparator value */ dreg = regs->clkc; /* Release the TOD clock update lock */ release_lock (&sysblk.todlock); /* Obtain the interrupt lock */ obtain_lock (&sysblk.intlock); /* reset the clock comparator pending flag according to the setting of the tod clock */ if( (sysblk.todclk + regs->todoffset) > dreg ) { ON_IC_CLKC(regs); /* Roll back the instruction and take the timer interrupt if we have a pending CPU timer and we are enabled for such interrupts *JJ */ if( OPEN_IC_CLKC(regs) ) { regs->psw.IA -= regs->psw.ilc; regs->psw.IA &= ADDRESS_MAXWRAP(regs); release_lock (&sysblk.intlock); RETURN_INTCHECK(regs); } } else OFF_IC_CLKC(regs); /* Release the interrupt lock */ release_lock (&sysblk.intlock); /* Shift out the epoch */ dreg <<= 8; /* Store clock comparator value at operand location */ ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); // /*debug*/logmsg("Store clock comparator=%16.16llX\n", dreg); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B6 STCTL - Store Control [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(store_control) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, d; /* Integer work areas */ BYTE rwork[64]; /* Register work areas */ RS(inst, execflag, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); FW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_STCTL)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Copy control registers into work area */ for ( i = r1, d = 0; ; ) { /* Copy control register bits 32-63 to work area */ STORE_FW(rwork + d, regs->CR_L(i)); d += 4; /* Instruction is complete when r3 register is done */ if ( i == r3 ) break; /* Update register number, wrapping from 15 to 0 */ i++; i &= 15; } /* Store control register contents at operand address */ ARCH_DEP(vstorec) ( rwork, d-1, effective_addr2, b2, regs ); } /* end DEF_INST(store_control) */ /*-------------------------------------------------------------------*/ /* B212 STAP - Store CPU Address [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_cpu_address) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); ODD_CHECK(effective_addr2, regs); /* Store CPU address at operand address */ ARCH_DEP(vstore2) ( regs->cpuad, effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* B202 STIDP - Store CPU ID [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_cpu_id) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word workarea */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); DW_CHECK(effective_addr2, regs); /* Load the CPU ID */ dreg = sysblk.cpuid; /* If first digit of serial is zero, insert processor id */ if ((dreg & 0x00F0000000000000ULL) == 0) dreg |= (U64)(regs->cpuad & 0x0F) << 52; /* Store CPU ID at operand address */ ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* B209 STPT - Store CPU Timer [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_cpu_timer) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word workarea */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[3] & SIE_IC3_SPT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Obtain the TOD clock update lock */ obtain_lock (&sysblk.todlock); /* Save the CPU timer value */ dreg = --regs->ptimer; /* Release the TOD clock update lock */ release_lock (&sysblk.todlock); /* Obtain the interrupt lock */ obtain_lock (&sysblk.intlock); /* reset the cpu timer pending flag according to its value */ if( (S64)regs->ptimer < 0 ) { ON_IC_PTIMER(regs); /* Roll back the instruction and take the timer interrupt if we have a pending CPU timer and we are enabled for such interrupts *JJ */ if( OPEN_IC_PTIMER(regs) ) { /* Release the interrupt lock */ release_lock (&sysblk.intlock); regs->psw.IA -= regs->psw.ilc; regs->psw.IA &= ADDRESS_MAXWRAP(regs); RETURN_INTCHECK(regs); } } else OFF_IC_PTIMER(regs); /* Release the interrupt lock */ release_lock (&sysblk.intlock); /* Store CPU timer value at operand location */ ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); // /*debug*/logmsg("Store CPU timer=%16.16llX\n", dreg); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B211 STPX - Store Prefix [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_prefix) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); FW_CHECK(effective_addr2, regs); /* Store prefix register at operand address */ ARCH_DEP(vstore4) ( regs->PX, effective_addr2, b2, regs ); } #ifdef FEATURE_STORE_SYSTEM_INFORMATION /*-------------------------------------------------------------------*/ /* B27D STSI - Store System Information [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_system_information) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RADR n; /* Absolute address */ int i; SYSIB111 *sysib111; /* Basic machine conf */ SYSIB121 *sysib121; /* Basic machine CPU */ SYSIB122 *sysib122; /* Basic machine CPUs */ #if 0 SYSIB221 *sysib221; /* LPAR CPU */ SYSIB222 *sysib222; /* LPAR CPUs */ SYSIB322 *sysib322; /* VM CPUs */ SYSIBVMDB *sysib322; /* VM description block */ #endif static BYTE manufact[16] = { 0xD1,0xC1,0xD5,0xD1,0xC1,0xC5,0xC7,0xC5, 0xD9,0x40,0x40,0x40,0x40,0x40,0x40,0x40 }; static BYTE plant[4] = { 0xE9,0xE9,0x40,0x40 }; static BYTE hexebcdic[16] = { 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7, 0xF8,0xF9,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6 }; static BYTE model[8] = { 0xC8,0xC5,0xD9,0xC3,0xE4,0xD3,0xC5,0xE2 }; static BYTE mpfact[32] = { 0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B, 0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B, 0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B, 0x00,0x4B,0x00,0x4B,0x00,0x4B,0x00,0x4B }; #define STSI_CAPACITY 2 S(inst, execflag, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); /* Check function code */ if((regs->GR_L(0) & STSI_GPR0_FC_MASK) > STSI_GPR0_FC_BASIC) { regs->psw.cc = 3; return; } /* Program check if reserved bit not zero */ if(regs->GR_L(0) & STSI_GPR0_RESERVED || regs->GR_L(1) & STSI_GPR1_RESERVED) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Return current level if function code is zero */ if((regs->GR_L(0) & STSI_GPR0_FC_MASK) == STSI_GPR0_FC_CURRENT) { regs->GR_L(0) |= STSI_GPR0_FC_BASIC; // regs->GR_L(0) |= STSI_GPR0_FC_LPAR; regs->psw.cc = 0; return; } /* Program check if operand not on a page boundary */ if ( effective_addr2 & 0x00000FFF ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc3 if selector codes invalid */ if( ((regs->GR_L(0) & STSI_GPR0_FC_MASK) == 0x10000000 && (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) == 1 && (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) > 1) || (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) == 0 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) == 0 || (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) > 2 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) > 2) { regs->psw.cc = 3; return; } /* Obtain absolute address of main storage block, check protection, and set reference and change bits */ n = LOGICAL_TO_ABS (effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); switch(regs->GR_L(0) & STSI_GPR0_FC_MASK) { case STSI_GPR0_FC_BASIC: switch(regs->GR_L(0) & STSI_GPR0_SEL1_MASK) { case 1: switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) { case 1: sysib111 = (SYSIB111*)(sysblk.mainstor + n); memset(sysib111, 0x00, sizeof(SYSIB111)); memcpy(sysib111->manufact,manufact,sizeof(manufact)); for(i = 0; i < 4; i++) sysib111->type[i] = hexebcdic[(sysblk.cpuid >> (28 - (i*4))) & 0x0F]; memset(sysib111->model, 0x40, sizeof(sysib111->model)); memcpy(sysib111->model, model, sizeof(model)); memset(sysib111->seqc,0xF0,sizeof(sysib111->seqc)); for(i = 0; i < 6; i++) sysib111->seqc[(sizeof(sysib111->seqc) - 6) + i] = hexebcdic[(sysblk.cpuid >> (52 - (i*4))) & 0x0F]; memcpy(sysib111->plant,plant,sizeof(plant)); regs->psw.cc = 0; break; default: regs->psw.cc = 3; } /* selector 2 */ break; case 2: switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) { case 1: sysib121 = (SYSIB121*)(sysblk.mainstor + n); memset(sysib121, 0x00, sizeof(SYSIB121)); memset(sysib121->seqc,0xF0,sizeof(sysib121->seqc)); for(i = 0; i < 6; i++) sysib121->seqc[(sizeof(sysib121->seqc) - 6) + i] = hexebcdic[sysblk.cpuid >> (52 - (i*4)) & 0x0F]; memcpy(sysib121->plant,plant,sizeof(plant)); STORE_HW(sysib121->cpuad,regs->cpuad); regs->psw.cc = 0; break; case 2: sysib122 = (SYSIB122*)(sysblk.mainstor + n); memset(sysib122, 0x00, sizeof(SYSIB122)); STORE_FW(sysib122->cap, STSI_CAPACITY); STORE_HW(sysib122->totcpu, MAX_CPU_ENGINES); STORE_HW(sysib122->confcpu, sysblk.numcpu); STORE_HW(sysib122->sbcpu, MAX_CPU_ENGINES - sysblk.numcpu); memcpy(sysib122->mpfact,mpfact,(MAX_CPU_ENGINES-1)*2); regs->psw.cc = 0; break; default: regs->psw.cc = 3; } /* selector 2 */ break; default: regs->psw.cc = 3; } /* selector 1 */ break; default: regs->psw.cc = 3; } /* function code */ } #endif /*FEATURE_STORE_SYSTEM_INFORMATION*/ /*-------------------------------------------------------------------*/ /* AC STNSM - Store Then And Systen Mask [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(store_then_and_system_mask) { BYTE i2; /* Immediate byte of opcode */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ #if defined(OPTION_REDUCED_INVAL) int realmode; int space; int armode; #endif SI(inst, execflag, regs, i2, b1, effective_addr1); PRIV_CHECK(regs); #if defined(OPTION_REDUCED_INVAL) realmode = REAL_MODE(®s->psw); armode = (regs->psw.armode == 1); space = (regs->psw.space == 1); #endif #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_STNSM)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Store current system mask value into storage operand */ ARCH_DEP(vstoreb) ( regs->psw.sysmask, effective_addr1, b1, regs ); INVALIDATE_AIA(regs); #if !defined(OPTION_REDUCED_INVAL) INVALIDATE_AEA_ALL(regs); #endif /* AND system mask with immediate operand */ regs->psw.sysmask &= i2; #if defined(OPTION_REDUCED_INVAL) if ((realmode != REAL_MODE(®s->psw)) || (armode != (regs->psw.armode == 1)) || (space != (regs->psw.space == 1))) INVALIDATE_AEA_ALL(regs); #endif SET_IC_EXTERNAL_MASK(regs); SET_IC_MCK_MASK(regs); SET_IC_IO_MASK(regs); SET_IC_PER_MASK(regs); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* AD STOSM - Store Then Or Systen Mask [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(store_then_or_system_mask) { BYTE i2; /* Immediate byte of opcode */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ SI(inst, execflag, regs, i2, b1, effective_addr1); PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[1] & SIE_IC1_STOSM)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Store current system mask value into storage operand */ ARCH_DEP(vstoreb) ( regs->psw.sysmask, effective_addr1, b1, regs ); /* OR system mask with immediate operand */ regs->psw.sysmask |= i2; #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* DAT must be off in XC mode */ if(regs->sie_state && (regs->siebk->mx & SIE_MX_XC) && (regs->psw.sysmask & PSW_DATMODE) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* For ECMODE, bits 0 and 2-4 of system mask must be zero */ if ( #if defined(FEATURE_BCMODE) regs->psw.ecmode && #endif /*defined(FEATURE_BCMODE)*/ (regs->psw.sysmask & 0xB8) != 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); SET_IC_EXTERNAL_MASK(regs); SET_IC_MCK_MASK(regs); SET_IC_IO_MASK(regs); SET_IC_PER_MASK(regs); INVALIDATE_AIA(regs); INVALIDATE_AEA_ALL(regs); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B246 STURA - Store Using Real Address [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(store_using_real_address) { int r1, r2; /* Values of R fields */ RADR n; /* Unsigned work */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); /* R2 register contains operand real storage address */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Program check if operand not on fullword boundary */ FW_CHECK(n, regs); /* Store R1 register at second operand location */ ARCH_DEP(vstore4) (regs->GR_L(r1), n, USE_REAL_ADDR, regs ); #if defined(FEATURE_PER2) /* Storage alteration must be enabled for STURA to be recognised */ if( EN_IC_PER_SA(regs) && EN_IC_PER_STURA(regs) ) { ON_IC_PER_SA(regs) ; ON_IC_PER_STURA(regs) ; regs->perc &= 0xFFFC; /* zero STD ID part of PER code */ } #endif /*defined(FEATURE_PER2)*/ } #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* B24C TAR - Test Access [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_access) { int r1, r2; /* Values of R fields */ U32 asteo; /* Real address of ASTE */ U32 aste[16]; /* ASN second table entry */ int protect; /* 1=ALE or page protection */ RRE(inst, execflag, regs, r1, r2); /* Program check if ASF control bit is zero */ if (!ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Set condition code 0 if ALET value is 0 */ if (regs->AR(r1) == ALET_PRIMARY) { regs->psw.cc = 0; return; } /* Set condition code 3 if ALET value is 1 */ if (regs->AR(r1) == ALET_SECONDARY) { regs->psw.cc = 3; return; } /* Perform ALET translation using EAX value from register R2 bits 0-15, and set condition code 3 if exception */ if (ARCH_DEP(translate_alet) (regs->AR(r1), regs->GR_LHH(r2), ACCTYPE_TAR, #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) (regs->sie_state && (regs->siebk->mx & SIE_MX_XC)) ? regs->hostregs : #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ regs, &asteo, aste, &protect)) { regs->psw.cc = 3; return; } /* Set condition code 1 or 2 according to whether the ALET designates the DUCT or the PASTE */ regs->psw.cc = (regs->AR(r1) & ALET_PRI_LIST) ? 2 : 1; } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* B22C TB - Test Block [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_block) { int r1, r2; /* Values of R fields */ RADR n; /* Real address */ RRE(inst, execflag, regs, r1, r2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); /* Load 4K block address from R2 register */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); n &= PAGEFRAME_PAGEMASK; /* Perform serialization */ PERFORM_SERIALIZATION (regs); /* Addressing exception if block is outside main storage */ if ( n >= regs->mainsize ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Protection exception if low-address protection is set */ if (ARCH_DEP(is_low_address_protected) (n, 0, 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); } /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Clear the 4K block to zeroes */ memset (sysblk.mainstor + n, 0x00, PAGEFRAME_PAGESIZE); /* Set condition code 0 if storage usable, 1 if unusable */ if (STORAGE_KEY(n) & STORKEY_BADFRM) regs->psw.cc = 1; else regs->psw.cc = 0; /* Perform serialization */ PERFORM_SERIALIZATION (regs); /* Clear general register 0 */ GR_A(0, regs) = 0; } /*-------------------------------------------------------------------*/ /* E501 TPROT - Test Protection [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_protection) { int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ RADR raddr; /* Real address */ RADR aaddr; /* Absolute address */ BYTE skey; /* Storage key */ BYTE akey; /* Access key */ int private = 0; /* 1=Private address space */ int protect = 0; /* 1=ALE or page protection */ int stid; /* Segment table indication */ U16 xcode; /* Exception code */ SSE(inst, execflag, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(regs->sie_state && (regs->siebk->ic[2] & SIE_IC2_TPROT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Convert logical address to real address */ if (REAL_MODE(®s->psw)) raddr = effective_addr1; else { /* Return condition code 3 if translation exception */ if (ARCH_DEP(translate_addr) (effective_addr1, b1, regs, ACCTYPE_TPROT, &raddr, &xcode, &private, &protect, &stid)) { regs->psw.cc = 3; return; } } /* Convert real address to absolute address */ aaddr = APPLY_PREFIXING (raddr, regs->PX); /* Program check if absolute address is outside main storage */ if (aaddr >= regs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(regs->sie_state && !regs->sie_pref) { U16 sie_xcode; int sie_private, sie_stid; /* Under SIE TPROT also indicates if the host is using page protection */ #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if (SIE_TRANSLATE_ADDR (regs->sie_mso + aaddr, b1, regs->hostregs, ACCTYPE_SIE, &aaddr, &sie_xcode, &sie_private, &protect, &sie_stid)) #else /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ if (SIE_TRANSLATE_ADDR (regs->sie_mso + aaddr, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, &aaddr, &sie_xcode, &sie_private, &protect, &sie_stid)) #endif /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert host real address to host absolute address */ aaddr = APPLY_PREFIXING (aaddr, regs->hostregs->PX); if (aaddr >= regs->hostregs->mainsize) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); } #endif /*defined(_FEATURE_SIE)*/ /* Load access key from operand 2 address bits 24-27 */ akey = effective_addr2 & 0xF0; /* Load the storage key for the absolute address */ skey = STORAGE_KEY(aaddr); /* Return condition code 2 if location is fetch protected */ if (ARCH_DEP(is_fetch_protected) (effective_addr1, skey, akey, private, regs)) regs->psw.cc = 2; else /* Return condition code 1 if location is store protected */ if (ARCH_DEP(is_store_protected) (effective_addr1, skey, akey, private, protect, regs)) regs->psw.cc = 1; else /* Return condition code 0 if location is not protected */ regs->psw.cc = 0; } #if defined(FEATURE_TRACING) /*-------------------------------------------------------------------*/ /* 99 TRACE - Trace [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(trace) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ #if defined(FEATURE_TRACING) U32 op; /* Operand */ #endif /*defined(FEATURE_TRACING)*/ RS(inst, execflag, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); FW_CHECK(effective_addr2, regs); #if defined(FEATURE_TRACING) /* Exit if explicit tracing (control reg 12 bit 31) is off */ if ( (regs->CR(12) & CR12_EXTRACE) == 0 ) return; /* Fetch the trace operand */ op = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Exit if bit zero of the trace operand is one */ if ( (op & 0x80000000) ) return; /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); regs->CR(12) = ARCH_DEP(trace_tr) (r1, r3, op, regs); #endif /*defined(FEATURE_TRACING)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } #endif /*defined(FEATURE_TRACING)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "control.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "control.c" #endif #endif /*!defined(_GEN_ARCH)*/