mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-05-19 00:32:33 +02:00
708 lines
22 KiB
C
708 lines
22 KiB
C
/* SIE.C (c) Copyright Jan Jaeger, 1999-2002 */
|
|
/* Interpretive Execution */
|
|
|
|
/* 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 */
|
|
|
|
/* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2002 */
|
|
|
|
// #define SIE_DEBUG
|
|
|
|
#include "hercules.h"
|
|
|
|
#include "opcode.h"
|
|
|
|
#include "inline.h"
|
|
|
|
#if !defined(_SIE_C)
|
|
|
|
#define _SIE_C
|
|
|
|
#if defined(_FEATURE_SIE)
|
|
int s370_run_sie (REGS *regs);
|
|
int s390_run_sie (REGS *regs);
|
|
#if defined(_900)
|
|
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_WAIT(_guestregs) \
|
|
((_guestregs)->psw.wait)
|
|
|
|
#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)
|
|
|
|
#endif /*!defined(_SIE_C)*/
|
|
|
|
#undef SIE_I_IO
|
|
#if !defined(FEATURE_ESAME)
|
|
#define SIE_I_IO(_guestregs) \
|
|
(((_guestregs)->siebk->v & SIE_V_IO) \
|
|
&& ((_guestregs)->psw.sysmask \
|
|
& ((_guestregs)->psw.ecmode ? PSW_IOMASK : 0xFE) ))
|
|
#else /*defined(FEATURE_ESAME)*/
|
|
#define SIE_I_IO(_guestregs) \
|
|
(((_guestregs)->siebk->v & SIE_V_IO) \
|
|
&& ((_guestregs)->psw.sysmask & PSW_IOMASK ))
|
|
#endif /*defined(FEATURE_ESAME)*/
|
|
|
|
#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 gpv = 0; /* guest psw validity */
|
|
int n; /* Loop counter */
|
|
U16 lhcpu; /* Last Host CPU address */
|
|
int icode; /* Interception code */
|
|
|
|
S(inst, execflag, regs, b2, effective_addr2);
|
|
|
|
SIE_MODE_XC_OPEX(regs);
|
|
|
|
PRIV_CHECK(regs);
|
|
|
|
SIE_INTERCEPT(regs);
|
|
|
|
if(!regs->psw.amode || !PRIMARY_SPACE_MODE(&(regs->psw)))
|
|
ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION);
|
|
|
|
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->ip);
|
|
#endif /*defined(SIE_DEBUG)*/
|
|
|
|
if(effective_addr2 > regs->mainsize - (sizeof(SIEBK)-1))
|
|
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
|
|
|
|
/* Direct pointer to state descriptor block */
|
|
STATEBK = (void*)(sysblk.mainstor + effective_addr2);
|
|
|
|
#if defined(FEATURE_ESAME)
|
|
if(STATEBK->mx & SIE_MX_ESAME)
|
|
{
|
|
GUESTREGS->arch_mode = ARCH_900;
|
|
GUESTREGS->sie_guestpi = (SIEFN)&z900_program_interrupt;
|
|
gpv = 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->sie_guestpi = (SIEFN)&s370_program_interrupt;
|
|
gpv = s370_load_psw(GUESTREGS, STATEBK->psw);
|
|
#else
|
|
// validation intercept
|
|
#endif
|
|
}
|
|
#endif /*!defined(FEATURE_ESAME)*/
|
|
else
|
|
if(STATEBK->m & SIE_M_XA)
|
|
{
|
|
GUESTREGS->arch_mode = ARCH_390;
|
|
GUESTREGS->sie_guestpi = (SIEFN)&s390_program_interrupt;
|
|
gpv = s390_load_psw(GUESTREGS, STATEBK->psw);
|
|
}
|
|
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;
|
|
}
|
|
|
|
#if defined(OPTION_REDUCED_INVAL)
|
|
INVALIDATE_AIA(GUESTREGS);
|
|
|
|
INVALIDATE_AEA_ALL(GUESTREGS);
|
|
#endif
|
|
|
|
/* Set host program interrupt routine */
|
|
GUESTREGS->sie_hostpi = (SIEFN)&ARCH_DEP(program_interrupt);
|
|
|
|
/* Prefered guest indication */
|
|
GUESTREGS->sie_pref = (STATEBK->m & SIE_M_VR) ? 1 : 0;
|
|
|
|
#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)*/
|
|
|
|
/* System Control Area Origin */
|
|
FETCH_FW(GUESTREGS->sie_scao, STATEBK->scao);
|
|
if(GUESTREGS->sie_scao >= sysblk.mainsize)
|
|
{
|
|
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
|
|
SIE_VI_WHY_SCADR, GUESTREGS);
|
|
STATEBK->c = SIE_C_VALIDITY;
|
|
return;
|
|
}
|
|
|
|
/* 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_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->mainsize,STATEBK->mse);
|
|
GUESTREGS->mainsize += 0x100000;
|
|
GUESTREGS->mainsize &= SIE2_MS_MASK;
|
|
|
|
if(GUESTREGS->sie_mso > GUESTREGS->mainsize)
|
|
{
|
|
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->mainsize -= 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->mainsize,STATEBK->mse);
|
|
GUESTREGS->mainsize = (GUESTREGS->mainsize + 1) << 16;
|
|
#endif /*!defined(FEATURE_ESAME)*/
|
|
|
|
/* Validate Guest prefix */
|
|
if(GUESTREGS->PX >= GUESTREGS->mainsize)
|
|
{
|
|
SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT,
|
|
SIE_VI_WHY_PFOUT, GUESTREGS);
|
|
STATEBK->c = SIE_C_VALIDITY;
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
/* 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);
|
|
|
|
/* Load the CPU timer */
|
|
FETCH_DW(GUESTREGS->ptimer, STATEBK->cputimer);
|
|
|
|
/* Reset the CPU timer pending flag according to its value */
|
|
if( (S64)GUESTREGS->ptimer < 0 )
|
|
ON_IC_PTIMER(GUESTREGS);
|
|
else
|
|
OFF_IC_PTIMER(GUESTREGS);
|
|
|
|
/* Load the TOD clock offset for this guest */
|
|
FETCH_DW(GUESTREGS->sie_epoch, STATEBK->epoch);
|
|
GUESTREGS->todoffset = regs->todoffset + (GUESTREGS->sie_epoch >> 8);
|
|
|
|
/* Load the clock comparator */
|
|
FETCH_DW(GUESTREGS->clkc, STATEBK->clockcomp);
|
|
GUESTREGS->clkc >>= 8; /* Internal Hercules format */
|
|
|
|
/* Reset the clock comparator pending flag according to
|
|
the setting of the TOD clock */
|
|
if( (sysblk.todclk + GUESTREGS->todoffset) > GUESTREGS->clkc )
|
|
ON_IC_CLKC(GUESTREGS);
|
|
else
|
|
OFF_IC_CLKC(GUESTREGS);
|
|
|
|
/* Load TOD Programmable Field */
|
|
FETCH_HW(GUESTREGS->todpr, STATEBK->todpf);
|
|
|
|
/* Load the guest registers */
|
|
memcpy(GUESTREGS->gr, regs->gr, 14 * sizeof(U64));
|
|
memcpy(GUESTREGS->ar, regs->ar, 16 * sizeof(U32));
|
|
memcpy(GUESTREGS->fpr, regs->fpr, 32 * sizeof(U32));
|
|
#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)
|
|
|| (GUESTREGS->sie_state != effective_addr2))
|
|
{
|
|
/* Absolute address of state descriptor block */
|
|
GUESTREGS->sie_state = 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);
|
|
}
|
|
|
|
/* Initialise the last fetched instruction pointer */
|
|
GUESTREGS->ip = GUESTREGS->inst;
|
|
|
|
/* Set SIE active */
|
|
GUESTREGS->instvalid = 0;
|
|
regs->sie_active = 1;
|
|
|
|
/* Get PSA pointer and ensure PSA is paged in */
|
|
if(GUESTREGS->sie_pref)
|
|
GUESTREGS->sie_psa = (PSA_3XX*)(sysblk.mainstor + GUESTREGS->PX);
|
|
else
|
|
GUESTREGS->sie_psa = (PSA_3XX*)(sysblk.mainstor
|
|
+ ARCH_DEP(logical_to_abs) (GUESTREGS->sie_mso
|
|
+ GUESTREGS->PX, USE_PRIMARY_SPACE, regs,
|
|
ACCTYPE_SIE, 0) );
|
|
|
|
#if !defined(FEATURE_ESAME)
|
|
/* If this is a S/370 guest, and the interval timer is enabled
|
|
then initialize the timer */
|
|
if( (STATEBK->m & SIE_M_370)
|
|
&& !(STATEBK->m & SIE_M_ITMOF))
|
|
{
|
|
S32 itimer,
|
|
olditimer;
|
|
U32 residue;
|
|
|
|
obtain_lock(&sysblk.todlock);
|
|
|
|
/* Set the interval timer pending according to the T bit
|
|
in the state control */
|
|
if(STATEBK->s & SIE_S_T)
|
|
ON_IC_ITIMER(GUESTREGS);
|
|
else
|
|
OFF_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->sie_psa->inttimer);
|
|
|
|
/* Bit position 23 of the interval timer is deremented
|
|
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->sie_psa->inttimer, itimer);
|
|
|
|
release_lock(&sysblk.todlock);
|
|
|
|
/* 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)*/
|
|
|
|
/* Early exceptions associated with the guest PSW */
|
|
if(gpv)
|
|
ARCH_DEP(program_interrupt) (GUESTREGS, gpv);
|
|
|
|
/* Run SIE in guests architecture mode */
|
|
icode = run_sie[GUESTREGS->arch_mode] (regs);
|
|
|
|
ARCH_DEP(sie_exit) (regs, icode);
|
|
|
|
/* Perform serialization and checkpoint synchronization */
|
|
PERFORM_SERIALIZATION (regs);
|
|
PERFORM_CHKPT_SYNC (regs);
|
|
}
|
|
|
|
|
|
/* Exit SIE state, restore registers and update the state descriptor */
|
|
void ARCH_DEP(sie_exit) (REGS *regs, int code)
|
|
{
|
|
int n;
|
|
|
|
#if defined(SIE_DEBUG)
|
|
logmsg(_("SIE: interception code %d\n"),code);
|
|
ARCH_DEP(display_inst) (GUESTREGS, GUESTREGS->instvalid ?
|
|
GUESTREGS->inst : NULL);
|
|
#endif /*defined(SIE_DEBUG)*/
|
|
|
|
/* Indicate we have left SIE mode */
|
|
regs->sie_active = 0;
|
|
|
|
/* zeroize interception status */
|
|
STATEBK->f = 0;
|
|
|
|
switch(code)
|
|
{
|
|
case SIE_HOST_INTERRUPT:
|
|
/* If a host interrupt is pending
|
|
then backup the psw and exit */
|
|
regs->psw.IA -= regs->psw.ilc;
|
|
regs->psw.IA &= ADDRESS_MAXWRAP(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 PGM_OPERATION_EXCEPTION:
|
|
STATEBK->c = SIE_C_OPEREXC;
|
|
break;
|
|
default:
|
|
STATEBK->c = SIE_C_PGMINT;
|
|
break;
|
|
}
|
|
|
|
/* Save CPU timer */
|
|
STORE_DW(STATEBK->cputimer, GUESTREGS->ptimer);
|
|
|
|
/* Save clock comparator */
|
|
GUESTREGS->clkc <<= 8; /* Internal Hercules format */
|
|
STORE_DW(STATEBK->clockcomp, GUESTREGS->clkc);
|
|
|
|
#if !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))
|
|
{
|
|
if(IS_IC_ITIMER(GUESTREGS))
|
|
STATEBK->s |= SIE_S_T;
|
|
else
|
|
STATEBK->s &= ~SIE_S_T;
|
|
}
|
|
#endif /*!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(U64));
|
|
memcpy(regs->ar, GUESTREGS->ar, 16 * sizeof(U32));
|
|
memcpy(regs->fpr, GUESTREGS->fpr, 32 * sizeof(U32));
|
|
#if defined(FEATURE_BINARY_FLOATING_POINT)
|
|
regs->fpc = GUESTREGS->fpc;
|
|
#endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/
|
|
|
|
/* 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 )
|
|
{
|
|
/* Indicate interception format 2 */
|
|
STATEBK->f |= SIE_F_IN;
|
|
|
|
#if defined(_FEATURE_PER)
|
|
/* Handle PER or concurrent PER event */
|
|
if( OPEN_IC_PERINT(GUESTREGS)
|
|
&& (GUESTREGS->psw.sysmask & PSW_PERMODE) )
|
|
{
|
|
PSA *psa;
|
|
#if defined(_FEATURE_PER2)
|
|
GUESTREGS->perc |= OPEN_IC_PERINT(GUESTREGS) >> ((32 - IC_CR9_SHIFT) - 16);
|
|
/* Positions 14 and 15 contain zeros if a storage alteration
|
|
event was not indicated */
|
|
if( !(OPEN_IC_PERINT(GUESTREGS) & IC_PER_SA)
|
|
|| (OPEN_IC_PERINT(GUESTREGS) & IC_PER_STURA) )
|
|
GUESTREGS->perc &= 0xFFFC;
|
|
|
|
#endif /*defined(_FEATURE_PER2)*/
|
|
/* Point to PSA fields in state descriptor */
|
|
psa = (void*)(sysblk.mainstor + GUESTREGS->sie_state + 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;
|
|
|
|
#endif /*defined(_FEATURE_PER)*/
|
|
|
|
/* Update interception parameters in the state descriptor */
|
|
if(GUESTREGS->inst[0] != 0x44)
|
|
{
|
|
if(GUESTREGS->instvalid)
|
|
memcpy(STATEBK->ipa, GUESTREGS->inst, GUESTREGS->psw.ilc);
|
|
}
|
|
else
|
|
{
|
|
int exilc;
|
|
STATEBK->f |= SIE_F_EX;
|
|
exilc = (GUESTREGS->exinst[0] < 0x40) ? 2 :
|
|
(GUESTREGS->exinst[0] < 0xC0) ? 4 : 6;
|
|
memcpy(STATEBK->ipa, GUESTREGS->exinst, exilc);
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/
|
|
|
|
|
|
#if defined(_FEATURE_SIE)
|
|
/* Execute guest instructions */
|
|
int ARCH_DEP(run_sie) (REGS *regs)
|
|
{
|
|
int icode;
|
|
|
|
SET_IC_EXTERNAL_MASK(GUESTREGS);
|
|
SET_IC_MCK_MASK(GUESTREGS);
|
|
SET_IC_IO_MASK(GUESTREGS);
|
|
SET_IC_PER_MASK(GUESTREGS);
|
|
#if defined(_FEATURE_PER)
|
|
/* Reset any PER pending indication */
|
|
OFF_IC_PER(GUESTREGS);
|
|
#endif /*defined(_FEATURE_PER)*/
|
|
|
|
do {
|
|
if(!(icode = setjmp(GUESTREGS->progjmp)))
|
|
while(! SIE_I_WAIT(GUESTREGS)
|
|
&& ! SIE_I_STOP(GUESTREGS)
|
|
&& ! SIE_I_EXT(GUESTREGS)
|
|
&& ! SIE_I_IO(GUESTREGS)
|
|
/* also exit if pending interrupts for the host cpu */
|
|
&& ! SIE_I_HOST(regs) )
|
|
{
|
|
|
|
if( SIE_IC_INTERRUPT_CPU(GUESTREGS) )
|
|
{
|
|
/* Process PER program interrupts */
|
|
if( OPEN_IC_PERINT(GUESTREGS) )
|
|
ARCH_DEP(program_interrupt) (GUESTREGS, PGM_PER_EVENT);
|
|
|
|
obtain_lock(&sysblk.intlock);
|
|
|
|
#if MAX_CPU_ENGINES > 1
|
|
/* Perform broadcasted purge of ALB and TLB if requested
|
|
synchronize_broadcast() must be called until there are
|
|
no more broadcast pending because synchronize_broadcast()
|
|
releases and reacquires the mainlock. */
|
|
|
|
while ((IS_IC_BROADCAST(regs)))
|
|
ARCH_DEP(synchronize_broadcast)(regs, 0, 0);
|
|
#endif /*MAX_CPU_ENGINES > 1*/
|
|
|
|
if( OPEN_IC_EXTPENDING(GUESTREGS) )
|
|
ARCH_DEP(perform_external_interrupt) (GUESTREGS);
|
|
|
|
release_lock(&sysblk.intlock);
|
|
}
|
|
|
|
GUESTREGS->instvalid = 0;
|
|
|
|
INSTRUCTION_FETCH(GUESTREGS->inst, GUESTREGS->psw.IA, GUESTREGS);
|
|
|
|
GUESTREGS->instvalid = 1;
|
|
|
|
#if defined(SIE_DEBUG)
|
|
/* Display the instruction */
|
|
ARCH_DEP(display_inst) (GUESTREGS, GUESTREGS->inst);
|
|
#endif /*defined(SIE_DEBUG)*/
|
|
|
|
regs->instcount++;
|
|
EXECUTE_INSTRUCTION(GUESTREGS->inst, 0, GUESTREGS);
|
|
|
|
#if defined(OPTION_CPU_UNROLL)
|
|
#ifdef FEATURE_PER
|
|
if (!PER_MODE(GUESTREGS))
|
|
#endif
|
|
{
|
|
regs->instcount += 7;
|
|
UNROLLED_EXECUTE(GUESTREGS);
|
|
UNROLLED_EXECUTE(GUESTREGS);
|
|
UNROLLED_EXECUTE(GUESTREGS);
|
|
UNROLLED_EXECUTE(GUESTREGS);
|
|
UNROLLED_EXECUTE(GUESTREGS);
|
|
UNROLLED_EXECUTE(GUESTREGS);
|
|
UNROLLED_EXECUTE(GUESTREGS);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(icode == 0 || icode == SIE_NO_INTERCEPT)
|
|
{
|
|
/* Check PER first, higher priority */
|
|
if( OPEN_IC_PERINT(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;
|
|
}
|
|
#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)*/
|