Files
org-hyperion-cules/sie.c
Fish (David B. Trout) 26a1f86d7f PTT facility enhancements:
1. Expand trace class to 64-bits.
2. Predefined convenience macros.
3. Expand trace message to 18 characters.
4. Use convenience macros where possible.

This commit is mostly in preparation for upcoming LCS debugging via PTT facility enhancements to help debug Issue #43 (which is a race condition and thus timing dependent, thus PTT debugging rather than logmsg debugging), but I tried to design it to make it easier for other modules (e.g. QETH) to also transition away from logmsg debugging to debugging via PTT facilty instead.
2015-01-24 06:16:05 -08:00

1436 lines
48 KiB
C

/* SIE.C (c) Copyright Jan Jaeger, 1999-2012 */
/* Interpretive Execution */
/* */
/* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2012 */
/* This module contains the SIE instruction as */
/* described in IBM S/370 Extended Architecture */
/* Interpretive Execution, SA22-7095-01 */
/* and */
/* Enterprise Systems Architecture / Extended Configuration */
/* Principles of Operation, SC24-5594-02 and SC24-5965-00 */
#include "hstdinc.h"
// #define SIE_DEBUG
//
#if !defined(_HENGINE_DLL_)
#define _HENGINE_DLL_
#endif
#if !defined(_SIE_C_)
#define _SIE_C_
#endif
#include "hercules.h"
#include "opcode.h"
#include "inline.h"
#if defined(_FEATURE_SIE)
#if !defined(_SIE_C)
#define _SIE_C
static int s370_run_sie (REGS *regs);
static int s390_run_sie (REGS *regs);
#if defined(_900)
static int z900_run_sie (REGS *regs);
#endif /*defined(_900)*/
static int (* run_sie[GEN_MAXARCH]) (REGS *regs) =
{
#if defined(_370)
s370_run_sie,
#endif
#if defined(_390)
s390_run_sie,
#endif
#if defined(_900)
z900_run_sie
#endif
};
#define GUESTREGS (regs->guestregs)
#define STATEBK ((SIEBK *)GUESTREGS->siebk)
#define SIE_I_STOP(_guestregs) \
((_guestregs)->siebk->v & SIE_V_STOP)
#define SIE_I_EXT(_guestregs) \
(((_guestregs)->siebk->v & SIE_V_EXT) \
&& ((_guestregs)->psw.sysmask & PSW_EXTMASK))
#define SIE_I_HOST(_hostregs) IC_INTERRUPT_CPU(_hostregs)
#if defined(SIE_DEBUG_PERFMON)
#define SIE_PERF_MAXNEG 0x1F
static int sie_perfmon[0x41 + SIE_PERF_MAXNEG];
#define SIE_PERFMON(_code) \
do { \
sie_perfmon[(_code) + SIE_PERF_MAXNEG] ++; \
} while(0)
#define SIE_PERF_PGMINT \
(code <= 0 ? code : (((code-1) & 0x3F)+1))
void *sie_perfmon_disp()
{
static char *dbg_name[] = {
/* -31 */ "SIE re-dispatch state descriptor",
/* -30 */ "SIE exit",
/* -29 */ "SIE run",
/* -28 */ "SIE runloop 1",
/* -27 */ "SIE runloop 2",
/* -26 */ "SIE interrupt check",
/* -25 */ "SIE execute instruction",
/* -24 */ "SIE unrolled execute",
/* -23 */ NULL,
/* -22 */ NULL,
/* -21 */ NULL,
/* -20 */ NULL,
/* -19 */ NULL,
/* -18 */ NULL,
/* -17 */ "SIE intercept I/O instruction",
/* -16 */ "SIE intercept I/O interrupt pending",
/* -15 */ "SIE intercept I/O interrupt",
/* -14 */ "SIE intercept PER interrupt",
/* -13 */ "SIE validity check",
/* -12 */ "SIE intercept external interrupt pending",
/* -11 */ "SIE intercept machine check interrupt",
/* -10 */ "SIE intercept restart interrupt",
/* -9 */ "SIE intercept stop request",
/* -8 */ "SIE intercept virtual machine wait",
/* -7 */ "SIE intercept I/O interrupt request",
/* -6 */ "SIE intercept external interrupt request",
/* -5 */ "SIE intercept instruction completion",
/* -4 */ "SIE intercept instruction",
/* -3 */ "SIE host program interrupt",
/* -2 */ "SIE host interrupt",
/* -1 */ "SIE no intercept",
/* 0 */ "SIE entry",
/* 01 */ "SIE intercept Operation exception",
/* 02 */ "SIE intercept Privileged-operation exception",
/* 03 */ "SIE intercept Execute exception",
/* 04 */ "SIE intercept Protection exception",
/* 05 */ "SIE intercept Addressing exception",
/* 06 */ "SIE intercept Specification exception",
/* 07 */ "SIE intercept Data exception",
/* 08 */ "SIE intercept Fixed-point-overflow exception",
/* 09 */ "SIE intercept Fixed-point-divide exception",
/* 0A */ "SIE intercept Decimal-overflow exception",
/* 0B */ "SIE intercept Decimal-divide exception",
/* 0C */ "SIE intercept HFP-exponent-overflow exception",
/* 0D */ "SIE intercept HFP-exponent-underflow exception",
/* 0E */ "SIE intercept HFP-significance exception",
/* 0F */ "SIE intercept HFP-floating-point-divide exception",
/* 10 */ "SIE intercept Segment-translation exception",
/* 11 */ "SIE intercept Page-translation exception",
/* 12 */ "SIE intercept Translation-specification exception",
/* 13 */ "SIE intercept Special-operation exception",
/* 14 */ "SIE intercept Pseudo-page-fault exception",
/* 15 */ "SIE intercept Operand exception",
/* 16 */ "SIE intercept Trace-table exception",
/* 17 */ "SIE intercept ASN-translation exception",
/* 18 */ "SIE intercept Page access exception",
/* 19 */ "SIE intercept Vector/Crypto operation exception",
/* 1A */ "SIE intercept Page state exception",
/* 1B */ "SIE intercept Page transition exception",
/* 1C */ "SIE intercept Space-switch event",
/* 1D */ "SIE intercept Square-root exception",
/* 1E */ "SIE intercept Unnormalized-operand exception",
/* 1F */ "SIE intercept PC-translation specification exception",
/* 20 */ "SIE intercept AFX-translation exception",
/* 21 */ "SIE intercept ASX-translation exception",
/* 22 */ "SIE intercept LX-translation exception",
/* 23 */ "SIE intercept EX-translation exception",
/* 24 */ "SIE intercept Primary-authority exception",
/* 25 */ "SIE intercept LFX-translation exception",
/* 26 */ "SIE intercept LSX-translation exception",
/* 27 */ "SIE intercept Control-switch exception",
/* 28 */ "SIE intercept ALET-specification exception",
/* 29 */ "SIE intercept ALEN-translation exception",
/* 2A */ "SIE intercept ALE-sequence exception",
/* 2B */ "SIE intercept ASTE-validity exception",
/* 2C */ "SIE intercept ASTE-sequence exception",
/* 2D */ "SIE intercept Extended-authority exception",
/* 2E */ "SIE intercept LSTE-sequence exception",
/* 2F */ "SIE intercept ASTE-instance exception",
/* 30 */ "SIE intercept Stack-full exception",
/* 31 */ "SIE intercept Stack-empty exception",
/* 32 */ "SIE intercept Stack-specification exception",
/* 33 */ "SIE intercept Stack-type exception",
/* 34 */ "SIE intercept Stack-operation exception",
/* 35 */ NULL,
/* 36 */ NULL,
/* 37 */ NULL,
/* 38 */ "SIE intercept ASCE-type exception",
/* 39 */ "SIE intercept Region-first-translation exception",
/* 3A */ "SIE intercept Region-second-translation exception",
/* 3B */ "SIE intercept Region-third-translation exception",
/* 3C */ NULL,
/* 3D */ NULL,
/* 3E */ NULL,
/* 3F */ NULL,
/* 40 */ "SIE intercept Monitor event" };
if(sie_perfmon[SIE_PERF_ENTER+SIE_PERF_MAXNEG])
{
int i;
for(i = 0; i < 0x61; i++)
if(sie_perfmon[i])
logmsg(MSG(HHC02285, "I" ,sie_perfmon[i],dbg_name[i]));
logmsg(MSG(HHC02286, "I",
(sie_perfmon[SIE_PERF_EXEC+SIE_PERF_MAXNEG] +
sie_perfmon[SIE_PERF_EXEC_U+SIE_PERF_MAXNEG]*7) /
sie_perfmon[SIE_PERF_ENTER+SIE_PERF_MAXNEG]));
}
else
logmsg(MSG(HHC02287, "I"));
}
#else
#define SIE_PERFMON(_code)
#endif
#endif /*!defined(_SIE_C)*/
#undef SIE_I_WAIT
#if defined(_FEATURE_WAITSTATE_ASSIST)
#define SIE_I_WAIT(_guestregs) \
(WAITSTATE(&(_guestregs)->psw) && !((_guestregs)->siebk->ec[0] & SIE_EC0_WAIA))
#else
#define SIE_I_WAIT(_guestregs) \
(WAITSTATE(&(_guestregs)->psw))
#endif
#undef SIE_I_IO
#if defined(FEATURE_BCMODE)
#define SIE_I_IO(_guestregs) \
(((_guestregs)->siebk->v & SIE_V_IO) \
&& ((_guestregs)->psw.sysmask \
& (ECMODE(&(_guestregs)->psw) ? PSW_IOMASK : 0xFE) ))
#else /*!defined(FEATURE_BCMODE)*/
#define SIE_I_IO(_guestregs) \
(((_guestregs)->siebk->v & SIE_V_IO) \
&& ((_guestregs)->psw.sysmask & PSW_IOMASK ))
#endif /*!defined(FEATURE_BCMODE)*/
#endif /*defined(_FEATURE_SIE)*/
#if defined(FEATURE_INTERPRETIVE_EXECUTION)
/*-------------------------------------------------------------------*/
/* B214 SIE - Start Interpretive Execution [S] */
/*-------------------------------------------------------------------*/
DEF_INST(start_interpretive_execution)
{
int b2; /* Values of R fields */
RADR effective_addr2; /* address of state desc. */
int n; /* Loop counter */
U16 lhcpu; /* Last Host CPU address */
volatile int icode; /* Interception code */
U64 dreg;
S(inst, regs, b2, effective_addr2);
SIE_INTERCEPT(regs);
PRIV_CHECK(regs);
PTT_SIE("SIE", regs->GR_L(14), regs->GR_L(15), (U32)(effective_addr2 & 0xffffffff));
SIE_PERFMON(SIE_PERF_ENTER);
#if !defined(FEATURE_ESAME) && !defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
if(!regs->psw.amode || !PRIMARY_SPACE_MODE(&(regs->psw)))
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
#endif
if((effective_addr2 & (sizeof(SIEBK)-1)) != 0
#if defined(FEATURE_ESAME)
|| (effective_addr2 & 0xFFFFFFFFFFFFF000ULL) == 0
|| (effective_addr2 & 0xFFFFFFFFFFFFF000ULL) == regs->PX)
#else /*!defined(FEATURE_ESAME)*/
|| (effective_addr2 & 0x7FFFF000) == 0
|| (effective_addr2 & 0x7FFFF000) == regs->PX)
#endif /*!defined(FEATURE_ESAME)*/
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
/* Perform serialization and checkpoint synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
#if defined(SIE_DEBUG)
logmsg(_("SIE: state descriptor " F_RADR "\n"),effective_addr2);
ARCH_DEP(display_inst) (regs, regs->instinvalid ? NULL : regs->ip);
#endif /*defined(SIE_DEBUG)*/
if(effective_addr2 > regs->mainlim - (sizeof(SIEBK)-1))
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/*
* As long as regs->sie_active is off, no serialization is
* required for GUESTREGS. sie_active should always be off here.
* Any other thread looking at sie_active holds the intlock.
*/
if (regs->sie_active)
{
OBTAIN_INTLOCK(regs);
regs->sie_active = 0;
RELEASE_INTLOCK(regs);
}
/* Initialize guestregs if first time */
if (GUESTREGS == NULL)
{
GUESTREGS = calloc_aligned(sizeof(REGS), 4096);
if (GUESTREGS == NULL)
{
logmsg(MSG(HHC00813, "E", PTYPSTR(regs->cpuad), regs->cpuad, "calloc()", strerror(errno)));
#if !defined(NO_SIGABEND_HANDLER)
signal_thread(sysblk.cputid[regs->cpuad], SIGUSR1);
#endif
return;
}
cpu_init (regs->cpuad, GUESTREGS, regs);
}
/* Direct pointer to state descriptor block */
GUESTREGS->siebk = (void*)(regs->mainstor + effective_addr2);
#if defined(FEATURE_ESAME)
if (STATEBK->mx & SIE_MX_ESAME)
{
GUESTREGS->arch_mode = ARCH_900;
GUESTREGS->program_interrupt = &z900_program_interrupt;
GUESTREGS->trace_br = (func)&z900_trace_br;
icode = z900_load_psw(GUESTREGS, STATEBK->psw);
}
#else /*!defined(FEATURE_ESAME)*/
if (STATEBK->m & SIE_M_370)
{
#if defined(_370)
GUESTREGS->arch_mode = ARCH_370;
GUESTREGS->program_interrupt = &s370_program_interrupt;
icode = s370_load_psw(GUESTREGS, STATEBK->psw);
#else
/* Validity intercept when 370 mode not installed */
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_370NI, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
#endif
}
#endif /*!defined(FEATURE_ESAME)*/
else
#if !defined(FEATURE_ESAME)
if (STATEBK->m & SIE_M_XA)
#endif /*!defined(FEATURE_ESAME)*/
{
GUESTREGS->arch_mode = ARCH_390;
GUESTREGS->program_interrupt = &s390_program_interrupt;
GUESTREGS->trace_br = (func)&s390_trace_br;
icode = s390_load_psw(GUESTREGS, STATEBK->psw);
}
#if !defined(FEATURE_ESAME)
else
{
/* Validity intercept for invalid mode */
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_MODE, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
#endif /*!defined(FEATURE_ESAME)*/
/* Prefered guest indication */
GUESTREGS->sie_pref = (STATEBK->m & SIE_M_VR) ? 1 : 0;
/* Load prefix from state descriptor */
FETCH_FW(GUESTREGS->PX, STATEBK->prefix);
GUESTREGS->PX &=
#if !defined(FEATURE_ESAME)
PX_MASK;
#else /*defined(FEATURE_ESAME)*/
(GUESTREGS->arch_mode == ARCH_900) ? PX_MASK : 0x7FFFF000;
#endif /*defined(FEATURE_ESAME)*/
#if defined(FEATURE_REGION_RELOCATE)
if(STATEBK->mx & SIE_MX_RRF)
{
RADR mso, msl, eso = 0, esl = 0;
if(STATEBK->zone >= FEATURE_SIE_MAXZONES)
{
/* Validity intercept for invalid zone */
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_AZNNI, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
mso = (sysblk.zpb[STATEBK->zone].mso & 0xFFFFF) << 20;
msl = (sysblk.zpb[STATEBK->zone].msl & 0xFFFFF) << 20;
eso = (sysblk.zpb[STATEBK->zone].eso & 0xFFFFF) << 20;
esl = (sysblk.zpb[STATEBK->zone].esl & 0xFFFFF) << 20;
if(mso > msl)
{
/* Validity intercept for invalid zone */
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_MSDEF, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
/* Ensure addressing exceptions on incorrect zone defs */
if(mso > regs->mainlim || msl > regs->mainlim)
mso = msl = 0;
#if defined(SIE_DEBUG)
logmsg(_("SIE: zone %d: mso=" F_RADR " msl=" F_RADR "\n"),
STATEBK->zone, mso, msl);
#endif /*defined(SIE_DEBUG)*/
GUESTREGS->sie_pref = 1;
GUESTREGS->sie_mso = 0;
GUESTREGS->mainstor = &(sysblk.mainstor[mso]);
GUESTREGS->mainlim = msl - mso;
GUESTREGS->storkeys = &(STORAGE_KEY(mso, &sysblk));
GUESTREGS->sie_xso = eso;
GUESTREGS->sie_xsl = esl;
GUESTREGS->sie_xso *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT);
GUESTREGS->sie_xsl *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT);
}
else
#endif /*defined(FEATURE_REGION_RELOCATE)*/
{
GUESTREGS->mainstor = sysblk.mainstor;
GUESTREGS->storkeys = sysblk.storkeys;
if(STATEBK->zone)
{
/* Validity intercept for invalid zone */
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_AZNNZ, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
#if defined(FEATURE_ESAME)
/* Load main storage origin */
FETCH_DW(GUESTREGS->sie_mso,STATEBK->mso);
GUESTREGS->sie_mso &= SIE2_MS_MASK;
/* Load main storage extend */
FETCH_DW(GUESTREGS->mainlim,STATEBK->mse);
GUESTREGS->mainlim |= ~SIE2_MS_MASK;
if(GUESTREGS->sie_mso > GUESTREGS->mainlim)
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_MSDEF, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
/* Calculate main storage size */
GUESTREGS->mainlim -= GUESTREGS->sie_mso;
#else /*!defined(FEATURE_ESAME)*/
/* Load main storage origin */
FETCH_HW(GUESTREGS->sie_mso,STATEBK->mso);
GUESTREGS->sie_mso <<= 16;
/* Load main storage extend */
FETCH_HW(GUESTREGS->mainlim,STATEBK->mse);
GUESTREGS->mainlim = ((GUESTREGS->mainlim + 1) << 16) - 1;
#endif /*!defined(FEATURE_ESAME)*/
/* Load expanded storage origin */
GUESTREGS->sie_xso = STATEBK->xso[0] << 16
| STATEBK->xso[1] << 8
| STATEBK->xso[2];
GUESTREGS->sie_xso *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT);
/* Load expanded storage limit */
GUESTREGS->sie_xsl = STATEBK->xsl[0] << 16
| STATEBK->xsl[1] << 8
| STATEBK->xsl[2];
GUESTREGS->sie_xsl *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT);
}
/* Validate Guest prefix */
if(GUESTREGS->PX > GUESTREGS->mainlim)
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_PFOUT, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
/* System Control Area Origin */
FETCH_FW(GUESTREGS->sie_scao, STATEBK->scao);
#if defined(FEATURE_ESAME)
{
U32 sie_scaoh;
/* For ESAME insert the high word of the address */
FETCH_FW(sie_scaoh, STATEBK->scaoh);
GUESTREGS->sie_scao |= (RADR)sie_scaoh << 32;
}
#endif /*defined(FEATURE_ESAME)*/
if(GUESTREGS->sie_scao > regs->mainlim)
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_SCADR, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
/* Validate MSO */
if (GUESTREGS->sie_mso)
{
/* Preferred guest must have zero MSO */
if (GUESTREGS->sie_pref)
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_MSONZ, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
/* MCDS guest must have zero MSO */
if (STATEBK->mx & SIE_MX_XC)
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_MSODS, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
}
#if defined(FEATURE_VIRTUAL_ARCHITECTURE_LEVEL)
/* Set Virtual Architecture Level (Facility List) */
{
U32 fld;
int i;
BYTE *facility_mask;
for(i = 0; i < STFL_HBYTESIZE; i++)
GUESTREGS->facility_list[i] = regs->facility_list[i];
FETCH_FW(fld,STATEBK->fld);
if(fld > regs->mainlim)
{
// SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
// ZZ: FIXME SIE_VI_WHY_??ADR, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
if(fld & 0x7ffffff8)
{
facility_mask = &(regs->mainstor[fld]);
GUESTREGS->facility_list[0] &= (facility_mask[0]
#if defined(FEATURE_ESAME)
/* Prevent current architecture mode being masked */ | 0x40
#endif
);
for(i = 1; i < STFL_BYTESIZE; i++)
GUESTREGS->facility_list[i] &= facility_mask[i];
}
}
#endif /*defined(FEATURE_VIRTUAL_ARCHITECTURE_LEVEL)*/
#if !defined(FEATURE_ESAME)
/* Reference and Change Preservation Origin */
FETCH_FW(GUESTREGS->sie_rcpo, STATEBK->rcpo);
if (!GUESTREGS->sie_rcpo && !GUESTREGS->sie_pref)
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_RCZER, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
return;
}
#endif /*!defined(FEATURE_ESAME)*/
/* Load the CPU timer */
FETCH_DW(dreg, STATEBK->cputimer);
set_cpu_timer(GUESTREGS, dreg);
/* Load the TOD clock offset for this guest */
FETCH_DW(GUESTREGS->sie_epoch, STATEBK->epoch);
GUESTREGS->tod_epoch = regs->tod_epoch + tod2etod(GUESTREGS->sie_epoch);
/* Load the clock comparator */
FETCH_DW(GUESTREGS->clkc, STATEBK->clockcomp);
GUESTREGS->clkc = tod2etod(GUESTREGS->clkc); /* Internal Hercules format */
/* Load TOD Programmable Field */
FETCH_HW(GUESTREGS->todpr, STATEBK->todpf);
/* Load the guest registers */
memcpy(GUESTREGS->gr, regs->gr, 14 * sizeof(regs->gr[0]));
memcpy(GUESTREGS->ar, regs->ar, 16 * sizeof(regs->ar[0]));
memcpy(GUESTREGS->fpr, regs->fpr, 32 * sizeof(regs->fpr[0]));
#if defined(FEATURE_BINARY_FLOATING_POINT)
GUESTREGS->fpc = regs->fpc;
#endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/
/* Load GR14 */
FETCH_W(GUESTREGS->GR(14), STATEBK->gr14);
/* Load GR15 */
FETCH_W(GUESTREGS->GR(15), STATEBK->gr15);
/* Load control registers */
for(n = 0;n < 16; n++)
FETCH_W(GUESTREGS->CR(n), STATEBK->cr[n]);
FETCH_HW(lhcpu, STATEBK->lhcpu);
/*
* If this is not the last host cpu that dispatched this state
* descriptor then clear the guest TLB entries
*/
if (regs->cpuad != lhcpu
|| SIE_STATE(GUESTREGS) != effective_addr2)
{
SIE_PERFMON(SIE_PERF_ENTER_F);
/* Absolute address of state descriptor block */
SIE_STATE(GUESTREGS) = effective_addr2;
/* Update Last Host CPU address */
STORE_HW(STATEBK->lhcpu, regs->cpuad);
/* Purge guest TLB entries */
ARCH_DEP(purge_tlb) (GUESTREGS);
ARCH_DEP(purge_alb) (GUESTREGS);
}
/* Initialize interrupt mask and state */
SET_IC_MASK(GUESTREGS);
SET_IC_INITIAL_STATE(GUESTREGS);
SET_IC_PER(GUESTREGS);
/* Initialize accelerated address lookup values */
SET_AEA_MODE(GUESTREGS);
SET_AEA_COMMON(GUESTREGS);
INVALIDATE_AIA(GUESTREGS);
GUESTREGS->tracing = regs->tracing;
/*
* Do setjmp(progjmp) because translate_addr() may result in
* longjmp(progjmp) for addressing exceptions.
*/
if(!setjmp(GUESTREGS->progjmp))
{
/*
* Set sie_active to 1. This means other threads may now
* access guestregs when holding intlock.
* This is the *only* place sie_active is set to one.
*/
OBTAIN_INTLOCK(regs);
regs->sie_active = 1;
RELEASE_INTLOCK(regs);
/* Get PSA pointer and ensure PSA is paged in */
if(GUESTREGS->sie_pref)
{
GUESTREGS->psa = (PSA_3XX*)(GUESTREGS->mainstor + GUESTREGS->PX);
GUESTREGS->sie_px = GUESTREGS->PX;
}
else
{
if (ARCH_DEP(translate_addr) (GUESTREGS->sie_mso + GUESTREGS->PX,
USE_PRIMARY_SPACE, regs, ACCTYPE_SIE))
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_PFACC, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
OBTAIN_INTLOCK(regs);
regs->sie_active = 0;
RELEASE_INTLOCK(regs);
return;
}
/* Convert host real address to host absolute address */
GUESTREGS->sie_px = APPLY_PREFIXING (regs->dat.raddr, regs->PX);
if (regs->dat.protect || GUESTREGS->sie_px > regs->mainlim)
{
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
SIE_VI_WHY_PFACC, GUESTREGS);
STATEBK->c = SIE_C_VALIDITY;
OBTAIN_INTLOCK(regs);
regs->sie_active = 0;
RELEASE_INTLOCK(regs);
return;
}
GUESTREGS->psa = (PSA_3XX*)(GUESTREGS->mainstor + GUESTREGS->sie_px);
}
/* Intialize guest timers */
OBTAIN_INTLOCK(regs);
/* CPU timer */
if(cpu_timer(GUESTREGS) < 0)
ON_IC_PTIMER(GUESTREGS);
/* Clock comparator */
if( TOD_CLOCK(GUESTREGS) > GUESTREGS->clkc )
ON_IC_CLKC(GUESTREGS);
#if !defined(FEATURE_ESAME)
/* Interval timer if S/370 and timer is enabled */
if((STATEBK->m & SIE_M_370) && !(STATEBK->m & SIE_M_ITMOF))
{
S32 itimer, olditimer;
U32 residue;
/* Set the interval timer pending according to the T bit
in the state control */
if(STATEBK->s & SIE_S_T)
ON_IC_ITIMER(GUESTREGS);
/* Fetch the residu from the state descriptor */
FETCH_FW(residue,STATEBK->residue);
/* Fetch the timer value from location 80 */
FETCH_FW(olditimer,GUESTREGS->psa->inttimer);
/* Bit position 23 of the interval timer is decremented
once for each multiple of 3,333 usecs containded in
bit position 0-19 of the residue counter */
itimer = olditimer - ((residue / 3333) >> 4);
/* Store the timer back */
STORE_FW(GUESTREGS->psa->inttimer, itimer);
/* Set interrupt flag and interval timer interrupt pending
if the interval timer went from positive to negative */
if (itimer < 0 && olditimer >= 0)
ON_IC_ITIMER(GUESTREGS);
}
#endif /*!defined(FEATURE_ESAME)*/
RELEASE_INTLOCK(regs);
/* Early exceptions associated with the guest load_psw() */
if(icode)
GUESTREGS->program_interrupt (GUESTREGS, icode);
/* Run SIE in guests architecture mode */
icode = run_sie[GUESTREGS->arch_mode] (regs);
} /* if (setjmp(GUESTREGS->progjmp)) */
ARCH_DEP(sie_exit) (regs, icode);
/* Perform serialization and checkpoint synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
longjmp(regs->progjmp, SIE_NO_INTERCEPT);
}
/* Exit SIE state, restore registers and update the state descriptor */
void ARCH_DEP(sie_exit) (REGS *regs, int code)
{
int n;
if(pttclass & PTT_CL_SIE)
{
U32 nt1 = 0, nt2 = 0;
BYTE *ip;
if(!GUESTREGS->instinvalid)
{
if(GUESTREGS->ip[0] == 0x44
#if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)
|| (GUESTREGS->ip[0] == 0xc6 && !(GUESTREGS->ip[1] & 0x0f))
#endif /*defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/
)
{
ip = GUESTREGS->exinst;
nt2 = (GUESTREGS->ip[0] == 0x44) ? 0x44 : ((0xc6 << 8) | (GUESTREGS->ip[1] & 0x0f));
}
else
ip = GUESTREGS->ip;
nt1 = (ip[0] << 24) | (ip[1] << 16);
if(ILC(ip[0]) > 2)
nt1 |= (ip[2] << 8) | ip[3];
if(ILC(ip[0]) > 4)
nt2 |= (ip[4] << 24) | (ip[5] << 16);
}
PTT_SIE("*SIE", nt1, nt2, code);
}
#if defined(SIE_DEBUG)
logmsg(_("SIE: interception code %d\n"),code);
ARCH_DEP(display_inst) (GUESTREGS,
GUESTREGS->instinvalid ? NULL : GUESTREGS->ip);
#endif /*defined(SIE_DEBUG)*/
SIE_PERFMON(SIE_PERF_EXIT);
SIE_PERFMON(SIE_PERF_PGMINT);
/* Indicate we have left SIE mode */
OBTAIN_INTLOCK(regs);
regs->sie_active = 0;
RELEASE_INTLOCK(regs);
/* zeroize interception status */
STATEBK->f = 0;
switch(code > 0 ? code & ~PGM_PER_EVENT : code)
{
case SIE_HOST_INTERRUPT:
/* If a host interrupt is pending
then backup the psw and exit */
SET_PSW_IA(regs);
UPD_PSW_IA (regs, regs->psw.IA -REAL_ILC(regs));
break;
case SIE_HOST_PGMINT:
break;
case SIE_INTERCEPT_INST:
STATEBK->c = SIE_C_INST;
break;
case SIE_INTERCEPT_PER:
STATEBK->f |= SIE_F_IF;
/*fallthru*/
case SIE_INTERCEPT_INSTCOMP:
STATEBK->c = SIE_C_PGMINST;
break;
case SIE_INTERCEPT_WAIT:
STATEBK->c = SIE_C_WAIT;
break;
case SIE_INTERCEPT_STOPREQ:
STATEBK->c = SIE_C_STOPREQ;
break;
case SIE_INTERCEPT_IOREQ:
STATEBK->c = SIE_C_IOREQ;
break;
case SIE_INTERCEPT_EXTREQ:
STATEBK->c = SIE_C_EXTREQ;
break;
case SIE_INTERCEPT_EXT:
STATEBK->c = SIE_C_EXTINT;
break;
case SIE_INTERCEPT_VALIDITY:
STATEBK->c = SIE_C_VALIDITY;
break;
case SIE_INTERCEPT_IOINT:
case SIE_INTERCEPT_IOINTP:
STATEBK->c = SIE_C_IOINT;
break;
case SIE_INTERCEPT_IOINST:
STATEBK->c = SIE_C_IOINST;
break;
case PGM_OPERATION_EXCEPTION:
STATEBK->c = SIE_C_OPEREXC;
break;
default:
STATEBK->c = SIE_C_PGMINT;
break;
}
/* Save CPU timer */
STORE_DW(STATEBK->cputimer, cpu_timer(GUESTREGS));
/* Save clock comparator */
STORE_DW(STATEBK->clockcomp, etod2tod(GUESTREGS->clkc));
#if defined(_FEATURE_INTERVAL_TIMER) && !defined(FEATURE_ESAME)
/* If this is a S/370 guest, and the interval timer is enabled
then save the timer state control bit */
if( (STATEBK->m & SIE_M_370)
&& !(STATEBK->m & SIE_M_ITMOF))
{
/* Save the shadow interval timer */
s370_store_int_timer(regs);
if(IS_IC_ITIMER(GUESTREGS))
STATEBK->s |= SIE_S_T;
else
STATEBK->s &= ~SIE_S_T;
}
#endif /*defined(_FEATURE_INTERVAL_TIMER) && !defined(FEATURE_ESAME)*/
/* Save TOD Programmable Field */
STORE_HW(STATEBK->todpf, GUESTREGS->todpr);
/* Save GR14 */
STORE_W(STATEBK->gr14, GUESTREGS->GR(14));
/* Save GR15 */
STORE_W(STATEBK->gr15, GUESTREGS->GR(15));
/* Store the PSW */
if(GUESTREGS->arch_mode == ARCH_390)
s390_store_psw (GUESTREGS, STATEBK->psw);
#if defined(_370) || defined(_900)
else
#endif
#if defined(FEATURE_ESAME)
z900_store_psw (GUESTREGS, STATEBK->psw);
#else /*!defined(FEATURE_ESAME)*/
#if defined(_370)
s370_store_psw (GUESTREGS, STATEBK->psw);
#endif
#endif /*!defined(FEATURE_ESAME)*/
/* save control registers */
for(n = 0;n < 16; n++)
STORE_W(STATEBK->cr[n], GUESTREGS->CR(n));
/* Update the approprate host registers */
memcpy(regs->gr, GUESTREGS->gr, 14 * sizeof(regs->gr[0]));
memcpy(regs->ar, GUESTREGS->ar, 16 * sizeof(regs->ar[0]));
memcpy(regs->fpr, GUESTREGS->fpr, 32 * sizeof(regs->fpr[0]));
#if defined(FEATURE_BINARY_FLOATING_POINT)
regs->fpc = GUESTREGS->fpc;
#endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/
INVALIDATE_AIA(regs);
SET_AEA_MODE(regs);
/* Zeroize the interruption parameters */
memset(STATEBK->ipa, 0, 10);
if( STATEBK->c == SIE_C_INST
|| STATEBK->c == SIE_C_PGMINST
|| STATEBK->c == SIE_C_OPEREXC
|| STATEBK->c == SIE_C_IOINST )
{
/* Indicate interception format 2 */
STATEBK->f |= SIE_F_IN;
#if defined(_FEATURE_PER)
/* Handle PER or concurrent PER event */
if( OPEN_IC_PER(GUESTREGS)
&& ECMODE(&GUESTREGS->psw)
&& (GUESTREGS->psw.sysmask & PSW_PERMODE) )
{
PSA *psa;
#if defined(_FEATURE_PER2)
GUESTREGS->perc |= OPEN_IC_PER(GUESTREGS) >> ((32 - IC_CR9_SHIFT) - 16);
/* Positions 14 and 15 contain zeros if a storage alteration
event was not indicated */
if( !(OPEN_IC_PER_SA(GUESTREGS))
|| (OPEN_IC_PER_STURA(GUESTREGS)) )
GUESTREGS->perc &= 0xFFFC;
#endif /*defined(_FEATURE_PER2)*/
/* Point to PSA fields in state descriptor */
psa = (void*)(regs->mainstor + SIE_STATE(GUESTREGS) + SIE_IP_PSA_OFFSET);
STORE_HW(psa->perint, GUESTREGS->perc);
STORE_W(psa->peradr, GUESTREGS->peradr);
}
if (IS_IC_PER_IF(GUESTREGS))
STATEBK->f |= SIE_F_IF;
/* Reset any pending PER indication */
OFF_IC_PER(GUESTREGS);
#endif /*defined(_FEATURE_PER)*/
/* Backup to the previous instruction */
GUESTREGS->ip -= REAL_ILC(GUESTREGS);
if (GUESTREGS->ip < GUESTREGS->aip)
GUESTREGS->ip = GUESTREGS->inst;
/* Update interception parameters in the state descriptor */
if(GUESTREGS->ip[0] == 0x44
#if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)
|| (GUESTREGS->ip[0] == 0xc6 && !(GUESTREGS->ip[1] & 0x0f))
#endif /*defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/
)
{
int exilc;
STATEBK->f |= SIE_F_EX;
exilc = ILC(GUESTREGS->exinst[0]);
memcpy(STATEBK->ipa, GUESTREGS->exinst, exilc);
}
else
{
if(!GUESTREGS->instinvalid)
memcpy(STATEBK->ipa, GUESTREGS->ip, ILC(GUESTREGS->ip[0]));
}
}
}
#endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/
#if defined(_FEATURE_SIE)
/* Execute guest instructions */
static int ARCH_DEP(run_sie) (REGS *regs)
{
int i;
int icode; /* SIE longjmp intercept code */
BYTE oldv; /* siebk->v change check reference */
BYTE *ip; /* instruction pointer */
const zz_func *current_opcode_table;
register int *caplocked = &sysblk.caplocked[regs->cpuad];
LOCK *caplock = &sysblk.caplock[regs->cpuad];
SIE_PERFMON(SIE_PERF_RUNSIE);
#if defined(_FEATURE_PER)
/* Reset any PER pending indication */
OFF_IC_PER(GUESTREGS);
#endif /*defined(_FEATURE_PER)*/
#ifdef FEATURE_INTERVAL_TIMER
/* Load the shadow interval timer */
{
S32 itimer;
FETCH_FW(itimer,GUESTREGS->psa->inttimer);
set_int_timer(GUESTREGS, itimer);
}
#endif
do {
SIE_PERFMON(SIE_PERF_RUNLOOP_1);
if(!(icode = setjmp(GUESTREGS->progjmp)))
do
{
SIE_PERFMON(SIE_PERF_RUNLOOP_2);
/* Keep a copy if SIEBK 'v' field for later checks */
oldv=GUESTREGS->siebk->v;
/* Set `execflag' to 0 in case EXecuted instruction did progjmp */
GUESTREGS->execflag = 0;
if(
SIE_I_STOP(GUESTREGS)
|| SIE_I_EXT(GUESTREGS)
|| SIE_I_IO(GUESTREGS)
)
break;
if( SIE_IC_INTERRUPT_CPU(GUESTREGS) )
{
SIE_PERFMON(SIE_PERF_INTCHECK);
/* Process PER program interrupts */
if( OPEN_IC_PER(GUESTREGS) )
ARCH_DEP(program_interrupt) (GUESTREGS, PGM_PER_EVENT);
OBTAIN_INTLOCK(regs);
OFF_IC_INTERRUPT(GUESTREGS);
/* Set psw.IA and invalidate the aia */
INVALIDATE_AIA(GUESTREGS);
if( OPEN_IC_EXTPENDING(GUESTREGS) )
ARCH_DEP(perform_external_interrupt) (GUESTREGS);
if( ((STATEBK->ec[0] & SIE_EC0_IOA) || (STATEBK->ec[3] & SIE_EC3_SIGAA))
&& OPEN_IC_IOPENDING(GUESTREGS) )
{
PERFORM_SERIALIZATION (GUESTREGS);
PERFORM_CHKPT_SYNC (GUESTREGS);
ARCH_DEP (perform_io_interrupt) (GUESTREGS);
}
#if defined(_FEATURE_WAITSTATE_ASSIST)
/* Wait state assist */
if (WAITSTATE(&GUESTREGS->psw) && (STATEBK->ec[0] & SIE_EC0_WAIA))
{
/* Test for disabled wait PSW and issue message */
if( IS_IC_DISABLED_WAIT_PSW(GUESTREGS) )
{
RELEASE_INTLOCK(regs);
longjmp(GUESTREGS->progjmp, SIE_INTERCEPT_WAIT);
}
if(
SIE_I_STOP(GUESTREGS)
|| SIE_I_EXT(GUESTREGS)
|| SIE_I_IO(GUESTREGS)
|| SIE_I_HOST(regs)
)
{
RELEASE_INTLOCK(regs);
break;
}
SET_AEA_MODE(GUESTREGS);
{
struct timespec waittime;
U64 now = host_tod();
waittime.tv_sec = now / 1000000;
waittime.tv_nsec = ((now % 1000000) + 3333) * 1000;
#ifdef OPTION_MIPS_COUNTING
regs->waittod = now;
#endif
sysblk.waiting_mask |= regs->cpubit;
sysblk.intowner = LOCK_OWNER_NONE;
timed_wait_condition
( &regs->intcond, &sysblk.intlock, &waittime );
while (sysblk.syncing)
wait_condition (&sysblk.sync_bc_cond, &sysblk.intlock);
sysblk.intowner = regs->cpuad;
/* Remove CPU from the waiting mask; AND
* must be used to handle the rare case
* where the CPU was already removed from
* sysblk.waiting_mask during
* wait_condition.
*/
sysblk.waiting_mask &= ~(regs->cpubit);
#ifdef OPTION_MIPS_COUNTING
regs->waittime += host_tod() - regs->waittod;
regs->waittod = 0;
#endif
}
RELEASE_INTLOCK(regs);
break;
} /* end if(wait) */
#endif
RELEASE_INTLOCK(regs);
}
if(
SIE_I_WAIT(GUESTREGS)
)
break;
ip = INSTRUCTION_FETCH(GUESTREGS, 0);
current_opcode_table=GUESTREGS->ARCH_DEP(runtime_opcode_xxxx);
#if defined(SIE_DEBUG)
/* Display the instruction */
ARCH_DEP(display_inst) (GUESTREGS,
GUESTREGS->instinvalid ? NULL : ip);
#endif /*defined(SIE_DEBUG)*/
SIE_PERFMON(SIE_PERF_EXEC);
//regs->instcount++;
EXECUTE_INSTRUCTION(current_opcode_table, ip, GUESTREGS);
regs->instcount++;
SIE_PERFMON(SIE_PERF_EXEC_U);
/* BHe: I have tried several settings. But 2 unrolled */
/* executes gives (core i7 at my place) the best results. */
/* Even a do { } while(0); with several unrolled executes */
/* and without the 'i' was slower. That surprised me. */
for(i = 0; i < 128; i++)
{
UNROLLED_EXECUTE(current_opcode_table, GUESTREGS);
UNROLLED_EXECUTE(current_opcode_table, GUESTREGS);
}
regs->instcount += i * 2;
if (caplocked[0])
{
obtain_lock(caplock);
/* Greg must be proud of me */
release_lock(caplock);
}
} while( unlikely(!SIE_I_HOST(regs)
&& !SIE_I_WAIT(GUESTREGS)
&& !SIE_I_EXT(GUESTREGS)
&& !SIE_I_IO(GUESTREGS)
&& !SIE_INTERRUPT_PENDING(GUESTREGS)));
/******************************************/
/* ABOVE : Remain in SIE until... */
/* - A Host Interrupt is made pending */
/* - A Sie defined irpt becomes enabled */
/* - A guest interrupt is made pending */
/******************************************/
if(icode == 0 || icode == SIE_NO_INTERCEPT)
{
/* Check PER first, higher priority */
if( OPEN_IC_PER(GUESTREGS) )
ARCH_DEP(program_interrupt) (GUESTREGS, PGM_PER_EVENT);
if( SIE_I_EXT(GUESTREGS) )
icode = SIE_INTERCEPT_EXTREQ;
else
if( SIE_I_IO(GUESTREGS) )
icode = SIE_INTERCEPT_IOREQ;
else
if( SIE_I_STOP(GUESTREGS) )
icode = SIE_INTERCEPT_STOPREQ;
else
if( SIE_I_WAIT(GUESTREGS) )
icode = SIE_INTERCEPT_WAIT;
else
if( SIE_I_HOST(regs) )
icode = SIE_HOST_INTERRUPT;
}
} while(icode == 0 || icode == SIE_NO_INTERCEPT);
return icode;
}
#if defined(FEATURE_INTERPRETIVE_EXECUTION)
#if defined(FEATURE_REGION_RELOCATE)
/*-------------------------------------------------------------------*/
/* B23D STZP - Store Zone Parameter [S] */
/*-------------------------------------------------------------------*/
DEF_INST(store_zone_parameter)
{
int b2; /* Values of R fields */
RADR effective_addr2; /* address of state desc. */
ZPB zpb; /* Zone Parameter Block */
int zone; /* Zone number */
S(inst, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
PTT_IO("STZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L);
FW_CHECK(regs->GR(2), regs);
zone = regs->GR_LHLCL(1);
if(zone >= FEATURE_SIE_MAXZONES)
{
PTT_ERR("*STZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L);
regs->psw.cc = 3;
return;
}
STORE_W(zpb.mso,sysblk.zpb[zone].mso);
STORE_W(zpb.msl,sysblk.zpb[zone].msl);
STORE_W(zpb.eso,sysblk.zpb[zone].eso);
STORE_W(zpb.esl,sysblk.zpb[zone].esl);
ARCH_DEP(vstorec(&zpb, sizeof(ZPB)-1,regs->GR(2), 2, regs));
regs->psw.cc = 0;
}
/*-------------------------------------------------------------------*/
/* B23E SZP - Set Zone Parameter [S] */
/*-------------------------------------------------------------------*/
DEF_INST(set_zone_parameter)
{
int b2; /* Values of R fields */
RADR effective_addr2; /* address of state desc. */
ZPB zpb; /* Zone Parameter Block */
int zone; /* Zone number */
RADR mso, /* Main Storage Origin */
msl, /* Main Storage Length */
eso, /* Expanded Storage Origin */
esl; /* Expanded Storage Length */
S(inst, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
PTT_IO("SZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L);
FW_CHECK(regs->GR(2), regs);
zone = regs->GR_LHLCL(1);
if(zone == 0 || zone >= FEATURE_SIE_MAXZONES)
{
PTT_ERR("*SZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L);
regs->psw.cc = 3;
return;
}
ARCH_DEP(vfetchc(&zpb, sizeof(ZPB)-1,regs->GR(2), 2, regs));
FETCH_W(mso,zpb.mso);
FETCH_W(msl,zpb.msl);
FETCH_W(eso,zpb.eso);
FETCH_W(esl,zpb.esl);
#if defined(FEATURE_ESAME)
if( (mso & ~ZPB2_MS_VALID)
|| (msl & ~ZPB2_MS_VALID)
|| (eso & ~ZPB2_ES_VALID)
|| (esl & ~ZPB2_ES_VALID) )
ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
#endif /*defined(FEATURE_ESAME)*/
sysblk.zpb[zone].mso = mso;
sysblk.zpb[zone].msl = msl;
sysblk.zpb[zone].eso = eso;
sysblk.zpb[zone].esl = esl;
regs->psw.cc = 0;
}
#endif /*defined(FEATURE_REGION_RELOCATE)*/
#if defined(FEATURE_IO_ASSIST)
/*-------------------------------------------------------------------*/
/* B23F TPZI - Test Pending Zone Interrupt [S] */
/*-------------------------------------------------------------------*/
DEF_INST(test_pending_zone_interrupt)
{
int b2; /* Values of R fields */
RADR effective_addr2; /* address of state desc. */
U32 ioid; /* I/O interruption address */
U32 ioparm; /* I/O interruption parameter*/
U32 iointid; /* I/O interruption ident */
FWORD tpziid[3];
int zone; /* Zone number */
S(inst, regs, b2, effective_addr2);
PRIV_CHECK(regs);
SIE_INTERCEPT(regs);
PTT_IO("TPZI", regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L);
FW_CHECK(regs->GR(2), regs);
/* Perform serialization and checkpoint-synchronization */
PERFORM_SERIALIZATION (regs);
PERFORM_CHKPT_SYNC (regs);
zone = regs->GR_LHLCL(1);
if(zone >= FEATURE_SIE_MAXZONES)
{
PTT_ERR("*TPZI", regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L);
regs->psw.cc = 0;
return;
}
if( IS_IC_IOPENDING )
{
/* Obtain the interrupt lock */
OBTAIN_INTLOCK(regs);
/* Test (but don't clear!) pending interrupt, and set condition code */
if( ARCH_DEP(present_zone_io_interrupt) (&ioid, &ioparm,
&iointid, zone) )
/* Store the SSID word and I/O parameter if an interrupt was pending */
{
/* Store interruption parms */
STORE_FW(tpziid[0],ioid);
STORE_FW(tpziid[1],ioparm);
STORE_FW(tpziid[2],iointid);
/* Release the interrupt lock */
RELEASE_INTLOCK(regs);
ARCH_DEP(vstorec(&tpziid, sizeof(tpziid)-1,regs->GR(2), 2, regs));
regs->psw.cc = 1;
}
else
{
/* Release the interrupt lock */
RELEASE_INTLOCK(regs);
regs->psw.cc = 0;
}
}
else
regs->psw.cc = 0;
}
/*-------------------------------------------------------------------*/
/* DIAG 002 - Update Interrupt Interlock Control Bit in PMCW */
/*-------------------------------------------------------------------*/
void ARCH_DEP(diagnose_002) (REGS *regs, int r1, int r3)
{
DEVBLK *dev;
U32 newgr1;
/* Program check if the ssid including lcss is invalid */
SSID_CHECK(regs);
/* Locate the device block for this subchannel */
dev = find_device_by_subchan (regs->GR_L(1));
/* Condition code 3 if subchannel does not exist,
is not valid, or is not enabled */
if (dev == NULL
|| (dev->pmcw.flag5 & PMCW5_V) == 0
|| (dev->pmcw.flag5 & PMCW5_E) == 0)
{
PTT_ERR("*DIAG002", regs->GR_L(r1),regs->GR_L(r3),regs->GR_L(1));
regs->psw.cc = 3;
return;
}
/* Obtain the device lock */
obtain_lock (&dev->lock);
/* Set newgr1 to the current value of pending and interlock control */
newgr1 = ((dev->scsw.flag3 & SCSW3_SC_PEND)
|| (dev->pciscsw.flag3 & SCSW3_SC_PEND)) ? 0x02 : 0;
if(dev->pmcw.flag27 & PMCW27_I)
newgr1 |= 0x01;
/* Do a compare-and-swap operation on the interrupt interlock
control bit where both interlock and pending bits are
compared, but only the interlock bit is swapped */
if((regs->GR_L(r1) & 0x03) == newgr1)
{
dev->pmcw.flag27 &= ~PMCW27_I;
dev->pmcw.flag27 |= (regs->GR_L(r3) & 0x01) ? PMCW27_I : 0;
regs->psw.cc = 0;
}
else
{
regs->GR_L(r1) &= ~0x03;
regs->GR_L(r1) |= newgr1;
regs->psw.cc = 1;
}
/* Release the device lock */
release_lock (&dev->lock);
}
#endif /*defined(FEATURE_IO_ASSIST)*/
#endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/
#endif
#if !defined(_GEN_ARCH)
#if defined(_ARCHMODE2)
#define _GEN_ARCH _ARCHMODE2
#include "sie.c"
#endif
#if defined(_ARCHMODE3)
#undef _GEN_ARCH
#define _GEN_ARCH _ARCHMODE3
#include "sie.c"
#endif
#endif /*!defined(_GEN_ARCH)*/