1 /*ECPSVM.C      (c) Copyright Ivan Warren, 2003-2009                 */
2 /*              Hercules ECPS:VM Support                             */
3 
4 /***********************************************************/
5 /*                                                         */
6 /* General guidelines about E6XX instruction class         */
7 /* this is an implementation of ECPS:VM Level 20           */
8 /*                                                         */
9 /* General rule is : Only do what is safe to do. In doubt, */
10 /*                   give control to CP back (and act as   */
11 /*                   a NO-OP). All instructions have this  */
12 /*                   behaviour, therefore allowing only    */
13 /*                   partial implementation, or bypassing  */
14 /*                   tricky cases                          */
15 /*                                                         */
16 /* NOTE : ECPS:VM is only available for S/370 architecture */
17 /*                                                         */
18 /* In order for CP ASSIST to be active, a CONFIGURATION    */
19 /* statement is added : ECPS:VM lvl|no                     */
20 /* lvl is the ASSIST level (20 is recommended)             */
21 /* no means CP ASSIST is disabled (default)                */
22 /*                                                         */
23 /* Currently supported CP ASSIST instructions :            */
24 /* +-----+-------+----------------------------------------+*/
25 /* |opc  | Mnemo | Function                               |*/
26 /* +-----+-------+----------------------------------------+*/
27 /* |E602 | LCKPG | Lock Page in core table                |*/
28 /* |E603 | ULKPG | Unlock page in core table              |*/
29 /* |E606 | SCNVU | Scan Virtual Unit control blocks       |*/
30 /* |E607 | DISP1 | Dispatcher assist                      |*/
31 /* |E608 | TRBRG | LRA + Basic checks on VPAGE            |*/
32 /* |E609 | TRLOK | Same as TRBRG + Lock page in core      |*/
33 /* |E60D | DISP0 | Dispatcher assist                      |*/
34 /* |E60E | SCNRU | Scan Real Unit control blocks          |*/
35 /* |E611 | DISP2 | Dispatcher assist                      |*/
36 /* |E612 | STLVL | Store ECPS:VM Level                    |*/
37 /* |E614 | FREEX | Allocate CP FREE Storage from subpool  |*/
38 /* |E615 | FRETX | Release CP FREE Storage to subpool     |*/
39 /* +-----+-------+----------------------------------------+*/
40 /*                                                         */
41 /* Currently supported VM ASSIST instructions :            */
42 /* +-----+-------+----------------------------------------+*/
43 /* |opc  | Mnemo | Function                               |*/
44 /* +-----+-------+----------------------------------------+*/
45 /* |0A   | SVC   | Virtual SVC Assist                     |*/
46 /* |80   | SSM   | Virtual SSM Assist                     |*/
47 /* |82   | LPSW  | Virtual LPSW Assist                    |*/
48 /* |B7   | LCTL  | Virtual LCTL Assist                    |*/
49 /* +-----+-------+----------------------------------------+*/
50 /*                                                         */
51 /***********************************************************/
52 
53 // $Log$
54 //
55 // Revision 1.83  2017/05/25 19:12:00  bobpolmanter/petercoghlan
56 // Fix DISP2 incorrect check of VMV370R and mis-loaded control registers;
57 // Remove DISP2 debug message causing page faults in CP.
58 //
59 // Revision 1.82  2017/04/30 13:54:00  bobpolmanter
60 // Enhancement revision; not implemented
61 //
62 // Revision 1.81  2017/03/27 14:10:00  bobpolmanter
63 // Fix two minor issues in DISP0 that did not match DMKDSPCH.
64 // Fix DISP0 to set VMPSWAIT on in exit #28.
65 //
66 // Revision 1.80  2017/02/18 14:05:00  bobpolmanter
67 // Enhancement revision; not implemented
68 //
69 // Revision 1.79  2017/02/10 07:25:00  bobpolmanter
70 // Enhancement revision; not implemented
71 //
72 // Revision 1.78  2017/02/05 08:15:00  bobpolmanter
73 // Enhancement revision; not implemented
74 //
75 // Revision 1.77  2017/02/04 15:45:00  bobpolmanter
76 // DISP2 dispatching user that is in virtual wait state;
77 //  add check for this condition and let CP handle it.
78 //
79 // Revision 1.76  2017/01/29 09:55:00  bobpolmanter
80 // DISP2 assist not completing for DAT-on guests due to incorrect
81 //  checking of shadow table and invalidate page table flags.
82 //
83 // Revision 1.75  2017/01/28 15:15:00  bobpolmanter
84 // Enhancement revision; not implemented
85 //
86 // Revision 1.74  2017/01/27 15:20:00  bobpolmanter
87 // Fix the reversed order of the EVM_ST operands in the CPEXBLOK FRET exit
88 //  of assist DISP2; was causing CP storage overlays and PRG001 failures.
89 //
90 // Revision 1.73  2017/01/27 15:20:00  bobpolmanter
91 // Enhancement revision; not implemented
92 //
93 // Revision 1.72  2017/01/24 12:53:00  bobpolmanter
94 // Instruction assists must go back to CP if virtual PSW in problem state
95 //
96 // Revision 1.71  2017/01/18 19:33:00  bobpolmanter
97 // Offset in PSA for APSTAT2 is incorrect in ecpsvm.h
98 //
99 // Revision 1.70  2017/01/15 12:00:00  bobpolmanter
100 // Virtual interval timer issue fixed in clock.c
101 //
102 // Revision 1.69  2017/01/12 12:00:00  bobpolmanter
103 // LCTL assist should not load DAS control regs 3-7;
104 // Update comments at beginning to reflect what is and is not supported
105 //
106 // Revision 1.68  2007/06/23 00:04:09  ivan
107 // Update copyright notices to include current year (2007)
108 //
109 // Revision 1.67  2007/01/13 07:18:14  bernard
110 // backout ccmask
111 //
112 // Revision 1.66  2007/01/12 15:22:37  bernard
113 // ccmask phase 1
114 //
115 // Revision 1.65  2006/12/31 17:53:48  gsmith
116 // 2006 Dec 31 Update ecpsvm.c for new psw IA scheme
117 //
118 // Revision 1.64  2006/12/08 09:43:20  jj
119 // Add CVS message log
120 //
121 
122 #include "hstdinc.h"
123 
124 #if !defined(_HENGINE_DLL_)
125 #define _HENGINE_DLL_
126 #endif
127 
128 #if !defined(_ECPSVM_C_)
129 #define _ECPSVM_C_
130 #endif
131 
132 #include "hercules.h"
133 
134 #include "opcode.h"
135 
136 #include "inline.h"
137 
138 #include "ecpsvm.h"
139 
140 #ifdef FEATURE_ECPSVM
141 
142 ECPSVM_CMDENT *ecpsvm_getcmdent(char *cmd);
143 
144 struct _ECPSVM_CPSTATS
145 {
146     ECPSVM_STAT_DCL(SVC);
147     ECPSVM_STAT_DCL(SSM);
148     ECPSVM_STAT_DCL(LPSW);
149     ECPSVM_STAT_DCL(STNSM);
150     ECPSVM_STAT_DCL(STOSM);
151     ECPSVM_STAT_DCL(SIO);
152     ECPSVM_STAT_DCL(VTIMER);
153     ECPSVM_STAT_DCL(STCTL);
154     ECPSVM_STAT_DCL(LCTL);
155     ECPSVM_STAT_DCL(DIAG);
156     ECPSVM_STAT_DCL(IUCV);
157 } ecpsvm_sastats={
158     ECPSVM_STAT_DEF(SVC),
159     ECPSVM_STAT_DEF(SSM),
160     ECPSVM_STAT_DEF(LPSW),
161     ECPSVM_STAT_DEFU(STNSM),
162     ECPSVM_STAT_DEFU(STOSM),
163     ECPSVM_STAT_DEFU(SIO),
164     ECPSVM_STAT_DEF(VTIMER),
165     ECPSVM_STAT_DEFU(STCTL),
166     ECPSVM_STAT_DEF(LCTL),
167     ECPSVM_STAT_DEFU(DIAG),
168     ECPSVM_STAT_DEFU(IUCV),
169 };
170 struct _ECPSVM_SASTATS
171 {
172     ECPSVM_STAT_DCL(FREE);
173     ECPSVM_STAT_DCL(FRET);
174     ECPSVM_STAT_DCL(LCKPG);
175     ECPSVM_STAT_DCL(ULKPG);
176     ECPSVM_STAT_DCL(SCNRU);
177     ECPSVM_STAT_DCL(SCNVU);
178     ECPSVM_STAT_DCL(DISP0);
179     ECPSVM_STAT_DCL(DISP1);
180     ECPSVM_STAT_DCL(DISP2);
181     ECPSVM_STAT_DCL(DNCCW);
182     ECPSVM_STAT_DCL(DFCCW);
183     ECPSVM_STAT_DCL(FCCWS);
184     ECPSVM_STAT_DCL(CCWGN);
185     ECPSVM_STAT_DCL(UXCCW);
186     ECPSVM_STAT_DCL(TRBRG);
187     ECPSVM_STAT_DCL(TRLOK);
188     ECPSVM_STAT_DCL(VIST);
189     ECPSVM_STAT_DCL(VIPT);
190     ECPSVM_STAT_DCL(STEVL);
191     ECPSVM_STAT_DCL(FREEX);
192     ECPSVM_STAT_DCL(FRETX);
193     ECPSVM_STAT_DCL(PMASS);
194     ECPSVM_STAT_DCL(LCSPG);
195 } ecpsvm_cpstats={
196     ECPSVM_STAT_DEFU(FREE),
197     ECPSVM_STAT_DEFU(FRET),
198     ECPSVM_STAT_DEF(LCKPG),
199     ECPSVM_STAT_DEF(ULKPG),
200     ECPSVM_STAT_DEF(SCNRU),
201     ECPSVM_STAT_DEF(SCNVU),
202     ECPSVM_STAT_DEF(DISP0),
203     ECPSVM_STAT_DEF(DISP1),
204     ECPSVM_STAT_DEF(DISP2),
205     ECPSVM_STAT_DEFU(DNCCW),
206     ECPSVM_STAT_DEFU(DFCCW),
207     ECPSVM_STAT_DEFU(FCCWS),
208     ECPSVM_STAT_DEFU(CCWGN),
209     ECPSVM_STAT_DEFU(UXCCW),
210     ECPSVM_STAT_DEF(TRBRG),
211     ECPSVM_STAT_DEF(TRLOK),
212     ECPSVM_STAT_DEFU(VIST),
213     ECPSVM_STAT_DEFU(VIPT),
214     ECPSVM_STAT_DEF(STEVL),
215     ECPSVM_STAT_DEF(FREEX),
216     ECPSVM_STAT_DEF(FRETX),
217     ECPSVM_STAT_DEFU(PMASS),
218     ECPSVM_STAT_DEFU(LCSPG),
219 };
220 
221 #define DEBUG_CPASSIST
222 #define DEBUG_SASSIST
223 
224 #define DODEBUG_ASSIST(_cond,x)  \
225 { \
226     if((_cond)) \
227     { \
228         x; \
229     }\
230 }
231 
232 #if defined(DEBUG_SASSIST)
233 #define DEBUG_SASSISTX(_inst,x) \
234 { \
235     DODEBUG_ASSIST(ecpsvm_sastats._inst.debug,x) \
236 }
237 #else
238 #define DEBUG_SASSISTX(_cond,x)
239 #endif
240 #if defined(DEBUG_CPASSIST)
241 #define DEBUG_CPASSISTX(_inst,x) \
242 { \
243     DODEBUG_ASSIST(ecpsvm_cpstats._inst.debug,x) \
244 }
245 #else
246 #define DEBUG_CPASSISTX(_cond,x)
247 #endif
248 
249 /* Utility macros because I am very lazy */
250 #define EVM_IC( x )  ARCH_DEP(vfetchb) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
251 #define EVM_LH( x )  ARCH_DEP(vfetch2) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
252 #define EVM_L( x )  ARCH_DEP(vfetch4) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
253 #define EVM_LD( x )  ARCH_DEP(vfetch8) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
254 #define EVM_STD( x , y ) ARCH_DEP(vstore8) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
255 #define EVM_ST( x , y ) ARCH_DEP(vstore4) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
256 #define EVM_STH( x , y ) ARCH_DEP(vstore2) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
257 #define EVM_STC( x , y ) ARCH_DEP(vstoreb) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs )
258 #define EVM_MVC( x , y , z ) ARCH_DEP(vfetchc) ( ( x ) , ( z ) , ( y ) , USE_REAL_ADDR , regs )
259 
260 #define BR14 UPD_PSW_IA(regs, regs->GR_L(14))
261 
262 #define INITPSEUDOIP(_regs) \
263     do {    \
264         (_regs).ip=(BYTE*)"\0\0";  \
265     } while(0)
266 
267 #define INITPSEUDOREGS(_regs) \
268     do { \
269         memset(&(_regs),0,sysblk.regs_copy_len); \
270         INITPSEUDOIP((_regs)); \
271     } while(0)
272 
273 
274 #define CPASSIST_HIT(_stat) ecpsvm_cpstats._stat.hit++
275 
276 #define SASSIST_HIT(_stat) ecpsvm_sastats._stat.hit++
277 
278 #define SASSIST_LPSW(_regs) \
279     do { \
280         SET_PSW_IA(&(_regs)); \
281         UPD_PSW_IA(regs, _regs.psw.IA); \
282         regs->psw.cc=_regs.psw.cc; \
283         regs->psw.pkey=_regs.psw.pkey; \
284         regs->psw.progmask=_regs.psw.progmask; \
285     } \
286     while(0)
287 
288 
289 #define SASSIST_PROLOG( _instname) \
290     VADR amicblok; \
291     VADR vpswa; \
292     BYTE *vpswa_p; \
293     REGS vpregs; \
294     BYTE  micpend; \
295     U32   CR6; \
296     ECPSVM_MICBLOK micblok; \
297     BYTE micevma; \
298     BYTE micevma2; \
299     BYTE micevma3; \
300     BYTE micevma4; \
301     if(SIE_STATE(regs)) \
302         return(1); \
303     if(!PROBSTATE(&regs->psw)) \
304     { \
305           return(1); \
306     } \
307     if(!sysblk.ecpsvm.available) \
308     { \
309           DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" ECPS:VM Disabled in configuration\n"))); \
310           return(1); \
311     } \
312     if(!ecpsvm_sastats._instname.enabled) \
313     { \
314           DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" ECPS:VM Disabled by command\n"))); \
315           return(1); \
316     } \
317     CR6=regs->CR_L(6); \
318     regs->ecps_vtmrpt = NULL; /* Assume vtimer off until validated */ \
319     if(!(CR6 & ECPSVM_CR6_VMASSIST)) \
320     { \
321         DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : EVMA Disabled by guest\n"))); \
322         return(1); \
323     } \
324     /* 2017-01-24  Reject if Virtual PSW is in problem state */ \
325     /* All instruction assists should be rejected if VPSW is in problem state and be reflected back    */  \
326     /* to CP for handling.  This affects 2nd level VM hosting 3rd level guests.                        */  \
327     if(CR6 & ECPSVM_CR6_VIRTPROB) \
328     { \
329         DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" reject : Virtual problem state\n"))); \
330         return(1); \
331     } \
332     /* End of 2017-01-24   */  \
333     /* Increment call now (don't count early misses) */ \
334     ecpsvm_sastats._instname.call++; \
335     amicblok=CR6 & ECPSVM_CR6_MICBLOK; \
336     /* Ensure MICBLOK resides on a single 2K page */ \
337     /* Then set ref bit by calling LOG_TO_ABS */ \
338     if((amicblok & 0x007ff) > 0x7e0) \
339     { \
340         DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" Micblok @ %6.6X crosses page frame\n"),amicblok)); \
341         return(1); \
342     } \
343     /* Load the micblok copy */ \
344     micblok.MICRSEG=EVM_L(amicblok); \
345     micblok.MICCREG=EVM_L(amicblok+4); \
346     micblok.MICVPSW=EVM_L(amicblok+8); \
347     micblok.MICWORK=EVM_L(amicblok+12); \
348     micblok.MICVTMR=EVM_L(amicblok+16); \
349     micblok.MICACF=EVM_L(amicblok+20); \
350     micpend=(micblok.MICVPSW >> 24); \
351     vpswa=micblok.MICVPSW & ADDRESS_MAXWRAP(regs); \
352     micevma=(micblok.MICACF >> 24); \
353     micevma2=((micblok.MICACF & 0x00ff0000) >> 16); \
354     micevma3=((micblok.MICACF & 0x0000ff00) >> 8); \
355     micevma4=(micblok.MICACF  & 0x000000ff); \
356     if((CR6 & ECPSVM_CR6_VIRTTIMR)) \
357     { \
358         regs->ecps_vtmrpt = MADDR(micblok.MICVTMR,USE_REAL_ADDR,regs,ACCTYPE_READ,0); \
359     } \
360     /* Set ref bit on page where Virtual PSW is stored */ \
361     vpswa_p=MADDR(vpswa,USE_REAL_ADDR,regs,ACCTYPE_READ,0); \
362     DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" VPSWA= %8.8X Virtual "),vpswa)); \
363     DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" CR6= %8.8X\n"),CR6)); \
364     DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" MICVTMR= %8.8X\n"),micblok.MICVTMR)); \
365     DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" Real "))); \
366     DEBUG_SASSISTX(_instname,display_psw(regs)); \
367     /* Load the Virtual PSW in a temporary REGS structure */ \
368     INITPSEUDOREGS(vpregs); \
369     ARCH_DEP(load_psw) (&vpregs,vpswa_p); \
370     DEBUG_SASSISTX(_instname,display_psw(&vpregs)); \
371 
372 
373 
374 #define ECPSVM_PROLOG(_inst) \
375 int     b1, b2; \
376 VADR    effective_addr1, \
377         effective_addr2; \
378      SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); \
379      PRIV_CHECK(regs); \
380      SIE_INTERCEPT(regs); \
381      if(!sysblk.ecpsvm.available) \
382      { \
383           DEBUG_CPASSISTX(_inst,logmsg(_("HHCEV300D : CPASSTS "#_inst" ECPS:VM Disabled in configuration "))); \
384           ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); \
385      } \
386      PRIV_CHECK(regs); /* No problem state please */ \
387      if(!ecpsvm_cpstats._inst.enabled) \
388      { \
389           DEBUG_CPASSISTX(_inst,logmsg(_("HHCEV300D : CPASSTS "#_inst" Disabled by command"))); \
390           return; \
391      } \
392      if(!(regs->CR_L(6) & 0x02000000)) \
393      { \
394         return; \
395      } \
396      ecpsvm_cpstats._inst.call++; \
397     DEBUG_CPASSISTX(_inst,logmsg(_("HHCEV300D : "#_inst" called\n")));
398 
399 
400 /* DISPx Utility macros */
401 
402 #define STPT(_x) \
403 { \
404     EVM_STD(cpu_timer(regs),_x); \
405 }
406 
407 #define SPT(_x) \
408 { \
409     set_cpu_timer(regs,EVM_LD(_x)); \
410     OBTAIN_INTLOCK(regs); \
411     if(CPU_TIMER(regs) < 0) \
412     { \
413         ON_IC_PTIMER(regs); \
414     } \
415     else \
416     { \
417         OFF_IC_PTIMER(regs); \
418     } \
419     RELEASE_INTLOCK(regs); \
420 }
421 
422 
423 #define CHARGE_STOP(_x) \
424 { \
425         STPT(_x+VMTTIME); \
426 }
427 
428 #define CHARGE_START(_x) \
429 { \
430     SPT(_x+VMTTIME); \
431 }
432 
433 #define CHARGE_SWITCH(_x,_y) \
434 { \
435     CHARGE_STOP(_x); \
436     CHARGE_START(_y); \
437     (_x)=(_y); \
438 }
439 
440 
441 int ecpsvm_do_fretx(REGS *regs,VADR block,U16 numdw,VADR maxsztbl,VADR fretl);
442 
443 /* CPASSIST FREE (Basic) Not supported */
444 /* This is part of ECPS:VM Level 18 and 19 */
445 /* ECPS:VM Level 20 use FREEX */
DEF_INST(ecpsvm_basic_freex)446 DEF_INST(ecpsvm_basic_freex)
447 {
448     ECPSVM_PROLOG(FREE);
449 }
450 /* CPASSIST FRET (Basic) Not supported */
451 /* This is part of ECPS:VM Level 18 and 19 */
452 /* ECPS:VM Level 20 use FRETX */
DEF_INST(ecpsvm_basic_fretx)453 DEF_INST(ecpsvm_basic_fretx)
454 {
455     ECPSVM_PROLOG(FRET);
456 }
457 
458 /* Lockpage common code (LCKPG/TRLOK) */
ecpsvm_lockpage1(REGS * regs,RADR cortab,RADR pg)459 static void ecpsvm_lockpage1(REGS *regs,RADR cortab,RADR pg)
460 {
461     BYTE corcode;
462     VADR corte;
463     U32  lockcount;
464     RADR cortbl;
465 
466     DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG coreptr = "F_RADR" Frame = "F_RADR"\n"),cortab,pg));
467     cortbl=EVM_L(cortab);
468     corte=cortbl+((pg & 0xfff000)>>8);
469     DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG corete = %6.6X\n"),corte));
470     corcode=EVM_IC(corte+8);
471     if(corcode & 0x80)
472     {
473         lockcount=EVM_L(corte+4);
474         lockcount++;
475     }
476     else
477     {
478         lockcount=1;
479         corcode|=0x80;
480         EVM_STC(corcode,corte+8);
481     }
482     EVM_ST(lockcount,corte+4);
483     DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG Page locked. Count = %6.6X\n"),lockcount));
484     return;
485 }
486 /* E602 LCKPG Instruction */
487 /* LCKPG D1(R1,B1),D2(R2,B2) */
488 /* 1st operand : PTR_PL -> Address of coretable */
489 /* 2nd Operand : Page address to be locked */
DEF_INST(ecpsvm_lock_page)490 DEF_INST(ecpsvm_lock_page)
491 {
492     VADR ptr_pl;
493     VADR pg;
494 
495     ECPSVM_PROLOG(LCKPG);
496 
497     ptr_pl=effective_addr1;
498     pg=effective_addr2;
499 
500     DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG PAGE=%6.6X, PTRPL=%6.6X\n"),pg,ptr_pl));
501 
502     ecpsvm_lockpage1(regs,ptr_pl,pg);
503     regs->psw.cc=0;
504     BR14;
505     CPASSIST_HIT(LCKPG);
506     return;
507 }
508 /* E603 ULKPG Instruction */
509 /* ULKPG D1(R1,B1),D2(R2,B2) */
510 /* 1st operand : PTR_PL -> +0 - Maxsize, +4 Coretable */
511 /* 2nd Operand : Page address to be unlocked */
DEF_INST(ecpsvm_unlock_page)512 DEF_INST(ecpsvm_unlock_page)
513 {
514     VADR ptr_pl;
515     VADR pg;
516     VADR corsz;
517     VADR cortbl;
518     VADR corte;
519     BYTE corcode;
520     U32  lockcount;
521 
522     ECPSVM_PROLOG(ULKPG);
523 
524     ptr_pl=effective_addr1;
525     pg=effective_addr2;
526 
527     DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG PAGE=%6.6X, PTRPL=%6.6X\n"),pg,ptr_pl));
528 
529     corsz=EVM_L(ptr_pl);
530     cortbl=EVM_L(ptr_pl+4);
531     if((pg+4095)>corsz)
532     {
533         DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG Page beyond core size of %6.6X\n"),corsz));
534         return;
535     }
536     corte=cortbl+((pg & 0xfff000)>>8);
537     corcode=EVM_IC(corte+8);
538     if(corcode & 0x80)
539     {
540         lockcount=EVM_L(corte+4);
541         lockcount--;
542     }
543     else
544     {
545         DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG Attempting to unlock page that is not locked\n")));
546         return;
547     }
548     if(lockcount==0)
549     {
550         corcode &= ~(0x80|0x02);
551         EVM_STC(corcode,corte+8);
552         DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG now unlocked\n")));
553     }
554     else
555     {
556         DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG Page still locked. Count = %6.6X\n"),lockcount));
557     }
558     EVM_ST(lockcount,corte+4);
559     CPASSIST_HIT(ULKPG);
560     BR14;
561     return;
562 }
563 /* DNCCW : Not supported */
DEF_INST(ecpsvm_decode_next_ccw)564 DEF_INST(ecpsvm_decode_next_ccw)
565 {
566     ECPSVM_PROLOG(DNCCW);
567 }
568 /* FCCWS : Not supported */
DEF_INST(ecpsvm_free_ccwstor)569 DEF_INST(ecpsvm_free_ccwstor)
570 {
571     ECPSVM_PROLOG(FCCWS);
572 }
573 /* SCNVU : Scan for Virtual Device blocks */
DEF_INST(ecpsvm_locate_vblock)574 DEF_INST(ecpsvm_locate_vblock)
575 {
576     U32  vdev;
577     U32  vchix;
578     U32  vcuix;
579     U32  vdvix;
580     VADR vchtbl;
581     VADR vch;
582     VADR vcu;
583     VADR vdv;
584 
585     ECPSVM_PROLOG(SCNVU);
586     vdev=regs->GR_L(1);
587     vchtbl=effective_addr1;
588 
589     vchix=EVM_LH(vchtbl+((vdev & 0xf00)>>7));   /* Get Index */
590     if(vchix & 0x8000)
591     {
592         DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU Virtual Device %4.4X has no VCHAN block\n"),vdev));
593         return;
594     }
595     vch=EVM_L(effective_addr2)+vchix;
596 
597     vcuix=EVM_LH(vch+8+((vdev & 0xf0)>>3));
598     if(vcuix & 0x8000)
599     {
600         DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU Virtual Device %4.4X has no VCU block\n"),vdev));
601         return;
602     }
603     vcu=EVM_L(effective_addr2+4)+vcuix;
604 
605     vdvix=EVM_LH(vcu+8+((vdev & 0xf)<<1));
606     if(vdvix & 0x8000)
607     {
608         DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU Virtual Device %4.4X has no VDEV block\n"),vdev));
609         return;
610     }
611     vdv=EVM_L(effective_addr2+8)+vdvix;
612     DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU %4.4X : VCH = %8.8X, VCU = %8.8X, VDEV = %8.8X\n"),
613                 vdev,
614                 vch,
615                 vcu,
616                 vdv));
617     regs->GR_L(6)=vch;
618     regs->GR_L(7)=vcu;
619     regs->GR_L(8)=vdv;
620     regs->psw.cc=0;
621     CPASSIST_HIT(SCNVU);
622     BR14;
623     return;
624 }
625 
626 /* DISP1 Core */
627 /* rc : 0 - Done */
628 /* rc : 1 - No-op */
629 /* rc : 2 - Invoke DISP2 */
ecpsvm_do_disp1(REGS * regs,VADR dl,VADR el)630 int ecpsvm_do_disp1(REGS *regs,VADR dl,VADR el)
631 {
632     VADR vmb;
633     U32 F_VMFLGS;       /* Aggregate for quick test */
634     U32 F_SCHMASK;      /* Flags to test */
635     U32 F_SCHMON;       /* Flags allowed on for quick dispatch */
636     VADR F_ASYSVM;      /* System VMBLOK */
637     VADR SCHDL;         /* SCHDL Exit */
638 
639     BYTE B_VMOSTAT;
640     BYTE B_VMQSTAT;
641     BYTE B_VMRSTAT;
642 
643     vmb=regs->GR_L(11);
644     DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Data list = %6.6X VM=%6.6X\n",dl,vmb));
645     F_VMFLGS=EVM_L(vmb+VMRSTAT);
646     F_SCHMASK=EVM_L(dl+64);
647     F_SCHMON=EVM_L(dl+68);
648     if((F_VMFLGS & F_SCHMASK) == F_SCHMON)
649     {
650         DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Quick Check complete\n"));
651         return(2);
652     }
653     else
654     {
655         DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Quick Check failed : %8.8X != %8.8X\n",(F_VMFLGS & F_SCHMASK),F_SCHMON));
656     }
657 
658     F_ASYSVM=EVM_L(ASYSVM);
659     if(vmb==F_ASYSVM)
660     {
661         DEBUG_CPASSISTX(DISP1,logmsg("DISP1 VMB is SYSTEM VMBLOCK\n"));
662         return(2);
663     }
664     SCHDL=EVM_L(el+4);
665     B_VMOSTAT=EVM_IC(vmb+VMOSTAT);
666     if(!(B_VMOSTAT & VMKILL))
667     {
668         DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Call SCHEDULE because VMKILL not set\n"));
669         UPD_PSW_IA(regs, SCHDL);
670         return(0);
671     }
672     B_VMQSTAT=EVM_IC(vmb+VMQSTAT);
673     if(!(B_VMQSTAT & VMCFREAD))
674     {
675         if(B_VMOSTAT & VMCF)
676         {
677             DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Call SCHEDULE because VMKILL & VMCF & !VMCFREAD set\n"));
678             UPD_PSW_IA(regs, SCHDL);
679             return(0);
680         }
681     }
682     /* At DSP - OFF */
683     B_VMQSTAT &= ~VMCFREAD;
684     B_VMOSTAT &= ~VMKILL;
685     EVM_STC(B_VMQSTAT,vmb+VMQSTAT);
686     EVM_STC(B_VMOSTAT,vmb+VMOSTAT);
687     B_VMRSTAT=EVM_IC(vmb+VMRSTAT);
688     if(B_VMRSTAT & VMLOGOFF)
689     {
690         DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Continue because already logging off\n"));
691         return(2);
692     }
693     B_VMRSTAT |= VMLOGOFF;
694     EVM_STC(B_VMRSTAT,vmb+VMRSTAT);
695     UPD_PSW_IA(regs, EVM_L(el+0));
696     DEBUG_CPASSISTX(DISP1,logmsg("DISP1 : Call USOFF\n"));
697     return(0);
698 }
699 
700 /* DISP2 Core */
ecpsvm_do_disp2(REGS * regs,VADR dl,VADR el)701 int ecpsvm_do_disp2(REGS *regs,VADR dl,VADR el)
702 {
703     VADR vmb;   /* Current VMBLOK */
704     VADR svmb;  /* ASYSVM */
705     VADR runu;  /* RUNUSER */
706     VADR lastu; /* LASTUSER */
707     VADR F_TRQB;
708     VADR F_CPEXB;
709     VADR F,B;
710     U16  HW1;
711     U32  FW1;
712     U64  DW1;
713     U32  CPEXBKUP[15];  /* CPEXBLOK Regs backup except GPR15 which is useless */
714     VADR F_ECBLOK;      /* Pointer to user's EC block for extended VM */
715     VADR F_CPEXADD;
716     U32  F_QUANTUM;
717     REGS wregs; /* Work REGS structure of PSW manipulation for Virtual PSW */
718     REGS rregs; /* Work REGS structure of PSW manipulation for Real    PSW */
719     int i;
720 
721     BYTE B_VMDSTAT,B_VMRSTAT,B_VMESTAT,B_VMPSTAT,B_VMMCR6,B_MICVIP;
722     BYTE B_VMOSTAT,B_VMPEND;
723     VADR F_MICBLOK;
724     U32 F_VMIOINT,F_VMPXINT;
725     U32 F_VMVCR0;
726     U32 NCR0,NCR1;
727     BYTE *work_p;
728 
729     vmb=regs->GR_L(11);
730     DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Data list=%6.6X VM=%6.6X\n",dl,vmb));
731     CHARGE_STOP(vmb);
732     if(EVM_IC(XTENDLOCK) == XTENDLOCKSET)
733     {
734         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Exit 8 : System extending\n"));
735         /* System in Extend process */
736         UPD_PSW_IA(regs, EVM_L(el+8));
737         return(0);
738     }
739     if(EVM_IC(APSTAT2) & CPMCHLK)
740     {
741         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Exit 8 : MCH Recovery\n"));
742         /* Machine Check recovery in progress */
743         UPD_PSW_IA(regs, EVM_L(el+8));
744         return(0);
745     }
746     svmb=EVM_L(ASYSVM);
747     /* Check IOB/TRQ for dispatch */
748     F_TRQB=EVM_L(dl+8);
749     if(F_TRQB!=dl)
750     {
751         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 TRQ/IOB @ %6.6X Exit being routed\n",F_TRQB));
752         /* We have a TRQ/IOB */
753         /* Update stack */
754         F=EVM_L(F_TRQB+8);
755         B=EVM_L(F_TRQB+12);
756         EVM_ST(F,B+8);
757         EVM_ST(B,F+12);
758         /* Get VMBLOK Responsible for this block */
759         vmb=EVM_L(F_TRQB+0x18);
760         /* Update stack count for the VMBLOK */
761         HW1=EVM_LH(vmb+VMSTKCNT);
762         HW1--;
763         EVM_STH(HW1,vmb+VMSTKCNT);
764         /* Start charging user for processor time */
765         CHARGE_START(vmb);
766         EVM_ST(vmb,STACKVM);
767         /* Update registers for TRQ/IOB exit */
768         regs->GR_L(10)=F_TRQB;
769         regs->GR_L(11)=vmb;
770         regs->GR_L(12)=EVM_L(F_TRQB+0x1C);
771         UPD_PSW_IA(regs, regs->GR_L(12));
772         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 TRQ/IOB @ %6.6X IA = %6.6X\n",F_TRQB,regs->GR_L(12)));
773         return(0);
774     }
775     /* Check CPEX BLOCK for dispatch */
776     F_CPEXB=EVM_L(dl+0);
777     if(F_CPEXB!=dl)
778     {
779         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 CPEXBLOK Exit being routed CPEX=%6.6X\n",F_CPEXB));
780         /* We have a CPEXBLOCK */
781         /* Update stack */
782         F=EVM_L(F_CPEXB+0);
783         B=EVM_L(F_CPEXB+4);
784         EVM_ST(F,B+0);
785         EVM_ST(B,F+4);
786         vmb=EVM_L(F_CPEXB+0x10+(11*4));
787         HW1=EVM_LH(vmb+VMSTKCNT);
788         HW1--;
789         EVM_STH(HW1,vmb+VMSTKCNT);
790         CHARGE_START(vmb);
791         /* Copy CPEXBLOCK Contents, and attempt FRET */
792         /* If fret fails, use exit #12 */
793         for(i=0;i<15;i++)
794         {
795             CPEXBKUP[i]=EVM_L(F_CPEXB+0x10+(i*4));
796         }
797         F_CPEXADD=EVM_L(F_CPEXB+0x0C);
798         if(ecpsvm_do_fretx(regs,F_CPEXB,10,EVM_L(dl+28),EVM_L(dl+32))!=0)
799         {
800             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 CPEXBLOK CPEX=%6.6X Fret Failed\n",F_CPEXB));
801             regs->GR_L(0)=10;
802             regs->GR_L(1)=F_CPEXB;
803             for(i=2;i<12;i++)
804             {
805                 regs->GR_L(i)=CPEXBKUP[i];
806             }
807         /* Save GPRS 12-1 (wraping) in DSPSAVE (datalist +40) */
808         /* So that LM 12,1,DSPSAVE in DMKDSP works after call to DMKFRET */
809         /* 2017-01-27 Fix order of EVM_ST operands to prevent stg overlays */
810             EVM_ST(CPEXBKUP[12],dl+40);
811             EVM_ST(CPEXBKUP[13],dl+44);
812             EVM_ST(CPEXBKUP[14],dl+48);
813             EVM_ST(EVM_L(F_CPEXB+12),dl+52); /* DSPSAVE + 12 = CPEXADD */
814             EVM_ST(CPEXBKUP[0],dl+56);
815             EVM_ST(CPEXBKUP[1],dl+60);  /* Note : DMKDSP Is wrong -  SCHMASK is at +64 (not +60) */
816         /* End of 2017-01-27 */
817         /* Upon taking this exit, GPRS 12-15 are same as entry */
818             UPD_PSW_IA(regs, EVM_L(el+12));
819             return(0);
820         }
821         for(i=0;i<15;i++)
822         {
823             regs->GR_L(i)=CPEXBKUP[i];
824         }
825         regs->GR_L(15)=F_CPEXADD;
826         UPD_PSW_IA(regs, F_CPEXADD);
827         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 CPEXBLOK CPEX=%6.6X IA=%6.6X\n",F_CPEXB,F_CPEXADD));
828         return(0);  /* CPEXBLOCK Branch taken */
829     }
830     /* Check for a USER run */
831     /* AT DMKDSP - DONE */
832     if(EVM_IC(CPSTAT2) & CPSHRLK)
833     {
834         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Exit 24 : CPSHRLK Set in CPSTAT2\n"));
835         UPD_PSW_IA(regs, EVM_L(el+24));  /* IDLEECPS */
836         return(0);
837     }
838     /* Scan Scheduler IN-Q */
839     DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Scanning Scheduler IN-Queue\n"));
840     FW1=EVM_L(dl+24);
841     for(vmb=EVM_L(FW1);vmb!=FW1;vmb=EVM_L(vmb))
842     {
843         /* 2017-02-04 Check for V PSW wait */
844         if(EVM_LH(vmb+VMPSW) & 0x0002)
845         {
846             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Not eligible : User in virtual PSW wait\n",vmb));
847             continue;
848         }
849         /* end of 2017-02-04 */
850         if(!(EVM_IC(vmb+VMDSTAT) & VMRUN))
851         {
852             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Not eligible : VMRUN not set\n",vmb));
853             continue;
854         }
855         if(EVM_IC(vmb+VMRSTAT) & VMCPWAIT)
856         {
857             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Not eligible : VMCPWAIT set\n",vmb));
858             continue;
859         }
860         if(EVM_IC(vmb+VMNOECPS))
861         {
862             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Exit 20 : VMB @ %6.6X Has VMNOECPS Set to %2.2X\n",vmb,EVM_IC(vmb+VMNOECPS)));
863             regs->GR_L(1)=vmb;
864             regs->GR_L(11)=EVM_L(ASYSVM);
865             UPD_PSW_IA(regs, EVM_L(el+20));  /* FREELOCK */
866             return(0);
867         }
868         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Will now be dispatched\n",vmb));
869         runu=EVM_L(RUNUSER);
870         F_QUANTUM=EVM_L(QUANTUM);
871         if(vmb!=runu)
872         {
873             /* User switching */
874             /* DMKDSP - FNDUSRD */
875             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : User switch from %6.6X to %6.6X\n",runu,vmb));
876             runu=EVM_L(RUNUSER);
877             EVM_STC(EVM_IC(runu+VMDSTAT) & ~VMDSP,runu+VMDSTAT);
878             lastu=EVM_L(LASTUSER);
879             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : RUNU=%6.6X, LASTU=%6.6X\n",runu,lastu));
880             if(lastu!=svmb && lastu!=vmb)
881             {
882                 if(EVM_IC(lastu+VMOSTAT) & VMSHR)       /* Running shared sys */
883                 {
884                     DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Exit 16 : LASTU=%6.6X has shared sys & LCSHPG not impl\n",lastu));
885                     CHARGE_START(lastu);
886                     /* LCSHRPG not implemented yet */
887                     regs->GR_L(10)=vmb;
888                     regs->GR_L(11)=lastu;
889                     UPD_PSW_IA(regs, EVM_L(el+16));
890                     return(0);
891                     /* A CHARGE_STOP(runu) is due when LCSHRPG is implemented */
892                 }
893             }
894         }
895         if(vmb!=runu || (vmb==runu && (F_QUANTUM & 0x80000000)))
896         {
897             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Restarting Time Slice\n"));
898             F_QUANTUM=EVM_L(dl+16);
899             if(EVM_IC(vmb+VMQLEVEL) & VMCOMP)
900             {
901                 F_QUANTUM <<= 2;
902             }
903         }
904         EVM_ST(F_QUANTUM,INTTIMER);
905         CHARGE_START(vmb);
906         EVM_ST(vmb,LASTUSER);
907         EVM_ST(vmb,RUNUSER);
908 
909 
910         /***  Prepare to run a user ***/
911 
912         /* Cache some important VMBLOK flag bytes */
913         B_VMDSTAT=EVM_IC(vmb+VMDSTAT);
914         B_VMRSTAT=EVM_IC(vmb+VMRSTAT);
915         B_VMPSTAT=EVM_IC(vmb+VMPSTAT);
916         B_VMESTAT=EVM_IC(vmb+VMESTAT);
917         B_VMOSTAT=EVM_IC(vmb+VMOSTAT);
918         B_VMPEND =EVM_IC(vmb+VMPEND);
919         B_VMMCR6=EVM_IC(vmb+VMMCR6);
920         F_MICBLOK=EVM_L(vmb+VMMCR6) & ADDRESS_MAXWRAP(regs);
921 
922         /* LOAD FPRS */
923         for(i=0;i<8;i+=2)
924         {
925             FW1=EVM_L(vmb+VMFPRS+(i*16));
926             regs->fpr[i*4]=FW1;
927             FW1=EVM_L(vmb+VMFPRS+(i*16)+4);
928             regs->fpr[i*4+1]=FW1;
929             FW1=EVM_L(vmb+VMFPRS+(i*16)+8);
930             regs->fpr[i*4+2]=FW1;
931             FW1=EVM_L(vmb+VMFPRS+(i*16)+12);
932             regs->fpr[i*4+3]=FW1;
933         }
934 
935         INITPSEUDOREGS(wregs);
936         work_p=MADDR(vmb+VMPSW,0,regs,USE_REAL_ADDR,0);
937         ARCH_DEP(load_psw) (&wregs,work_p);    /* Load user's Virtual PSW in work structure */
938         SET_PSW_IA(&wregs);
939 
940         /* Build REAL PSW */
941         INITPSEUDOREGS(rregs);
942         /* Copy IAR */
943         UPD_PSW_IA(&rregs, wregs.psw.IA);
944         /* Copy CC, PSW KEYs and PGM Mask */
945         rregs.psw.cc=wregs.psw.cc;
946         rregs.psw.pkey=wregs.psw.pkey;
947         /* Indicate Translation + I/O + Ext + Ecmode + Problem + MC */
948         rregs.psw.sysmask=0x07; /* I/O + EXT + Trans */
949         rregs.psw.states = BIT(PSW_EC_BIT)         /* ECMODE */
950                          | BIT(PSW_PROB_BIT)       /* Problem state */
951                          | BIT(PSW_MACH_BIT);      /* MC Enabled */
952         rregs.psw.intcode=0;    /* Clear intcode */
953         rregs.psw.progmask=wregs.psw.progmask;
954 
955         NCR0=EVM_L(CPCREG0);    /* Assume for now */
956         NCR1=EVM_L(vmb+VMSEG);  /* Ditto          */
957 
958         /* Disable ECPS:VM in VM-REAL CR6 For now */
959         B_VMMCR6&=~(VMMSHADT|VMMPROB|VMMNOSK|VMMFE);
960 
961         /* We load VMECEXT Even if it's not a ECMODE VM */
962         /* in which case F_ECBLOK is also Virtual CR0   */
963 
964         F_ECBLOK=EVM_L(vmb+VMECEXT);
965 
966         /* ECMODE VM ? */
967         if(B_VMPSTAT & VMV370R)
968         {
969             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X has ECMODE ON\n",vmb));
970             /* Is this an ECMODE PSW Machine ? */
971             if(B_VMESTAT & VMEXTCM)
972             {
973                 if((B_VMESTAT & (VMINVSEG|VMNEWCR0)) == (VMINVSEG|VMNEWCR0))
974                 {
975                     /* CP Say this is NOT good */
976                     /* Take exit 28 */
977                     logmsg(_("HHCEV004W : Abend condition detected in DISP2 instr\n"));
978                     UPD_PSW_IA(regs, EVM_L(el+28));
979                     return(0);
980                 }
981                 /* Check 3rd level translation */
982                 if(wregs.psw.sysmask & 0x04)
983                 {
984                     NCR0=EVM_L(F_ECBLOK+EXTSHCR0);
985                     NCR1=EVM_L(F_ECBLOK+EXTSHCR1);
986                     B_VMMCR6|=VMMSHADT;   /* re-enable Shadow Table management in CR6 */
987                 }
988             }
989 
990         }
991         /* Invalidate Shadow Tables if necessary */
992         /* 2017-01-29 if statement corrected */
993         if((B_VMESTAT & (VMINVPAG | VMSHADT)) == (VMINVPAG|VMSHADT))
994         {
995             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Refusing to simulate DMKVATAB\n",vmb));
996             /* Really looks like DMKVATAB is a huge thing to simulate */
997             /* My belief is that the assist can't handle this one     */
998             /* Return to caller as a NO-OP on this one                */
999             return(1);
1000             /* ecpsvm_inv_shadtab_pages(regs,vmb); */
1001         }
1002         B_VMESTAT&=~VMINVPAG;
1003         B_VMDSTAT|=VMDSP;
1004         /* Test for CPMICON in DMKDSP useless here */
1005         /* if CPMICON was off, we would have never */
1006         /* been called anyway                      */
1007         if(F_MICBLOK!=0)        /* That is SET ASSIST ON */
1008         {
1009             B_MICVIP=0;
1010             /* Check tracing (incompatible with assist) */
1011             if(!(EVM_IC(vmb+VMTRCTL) & (VMTRSVC|VMTRPRV|VMTRBRIN)))
1012             {
1013                 B_VMMCR6|=VMMFE;
1014                 if(B_VMOSTAT & VMSHR)
1015                 {
1016                     /* Cannot allow ISK/SSK in shared sys VM */
1017                     B_VMMCR6|=VMMNOSK;
1018                 }
1019                 if(PROBSTATE(&wregs.psw))
1020                 {
1021                     B_VMMCR6|=VMMPROB;
1022                 }
1023                 /* Set MICPEND if necessary */
1024                 /* (assist stuff to ensure LPSW/SSM/SVC sim */
1025                 /* does not re-enable VPSW when an interrupt */
1026                 /* is pending)                               */
1027                 while(1)
1028                 {
1029                     B_MICVIP=0;
1030                     F_VMIOINT=EVM_LH(vmb+VMIOINT);
1031                     if(EVM_LH(vmb+VMIOINT)!=0)
1032                         {
1033                         F_VMIOINT<<=16;
1034                         if(B_VMESTAT & VMEXTCM)
1035                         {
1036                             if(F_VMIOINT&=EVM_L(F_ECBLOK))
1037                             {
1038                                 B_MICVIP|=0x80;
1039                                 break;
1040                             }
1041                         }
1042                         else
1043                         {
1044                             B_MICVIP|=0x80;
1045                             break;
1046                         }
1047                     }
1048                     if(B_VMESTAT & VMEXTCM)
1049                     {
1050                         if(B_VMPEND & VMPGPND)
1051                         {
1052                             B_MICVIP|=0x80;
1053                         }
1054                     }
1055                     if(B_VMPSTAT & VMV370R)
1056                     {
1057                         F_VMVCR0=EVM_L(F_ECBLOK+0);
1058                     }
1059                     else
1060                     {
1061                         F_VMVCR0=F_ECBLOK;
1062                     }
1063                     for(F_VMPXINT=EVM_L(vmb+VMPXINT);F_VMPXINT;F_VMPXINT=EVM_L(F_VMPXINT)) /* XINTNEXT at +0 */
1064                     {
1065                         if(F_VMVCR0 & EVM_LH(F_VMPXINT+10))
1066                         {
1067                             B_MICVIP|=0x80;
1068                             break;
1069                         }
1070                     }
1071                     break;      /* Terminate dummy while loop */
1072                 } /* While dummy loop for MICPEND */
1073             } /* if(Not tracing) */
1074             EVM_STC(B_MICVIP,F_MICBLOK+8);      /* Save new MICVIP */
1075         } /* if(F_MICBLOCK!=0) */
1076         /* If an Extended VM, Load CRs 4-13 */
1077         /* CR6 Will be overwritten in a second */
1078         if(B_VMPSTAT & VMV370R)
1079         {
1080             for(i=4;i<14;i++)
1081             {
1082                 regs->CR_L(i)=EVM_L(F_ECBLOK+(i*4));
1083             }
1084         }
1085         /* Update VMMICRO */
1086         EVM_STC(B_VMMCR6,vmb+VMMCR6);
1087         /* Update PER Control */
1088         if(EVM_IC(vmb+VMTRCTL) & VMTRPER)
1089         {
1090             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : PER ON\n"));
1091             FW1=EVM_L(vmb+VMTREXT);
1092             regs->CR_L( 9)=EVM_L(FW1+0x1C);
1093             regs->CR_L(10)=EVM_L(FW1+0x20);
1094             regs->CR_L(11)=EVM_L(FW1+0x24);
1095             rregs.psw.sysmask |= 0x40;  /* PER Mask in PSW */
1096         }
1097         /* Update CR6 */
1098         regs->CR_L(6)=EVM_L(vmb+VMMCR6);
1099         /* Insure proper re-entry */
1100         EVM_ST(0,STACKVM);
1101         /* Update PROBLEM Start time */
1102         DW1=EVM_LD(vmb+VMTMOUTQ);
1103         EVM_STD(DW1,PROBSTRT);
1104 
1105         /* Checkpoint Interval Timer */
1106         FW1=EVM_L(INTTIMER);
1107         EVM_ST(FW1,QUANTUM);
1108 
1109         /* Update REAL CR0/CR1 */
1110         regs->CR_L(0)=NCR0;
1111         regs->CR_L(1)=NCR1;
1112 
1113         /* Indicate RUNNING a user */
1114         EVM_STC(CPRUN,CPSTATUS);
1115 
1116         /* Update real PSW with working PSW */
1117 
1118         /* Update regs */
1119         for(i=0;i<16;i++)
1120         {
1121             regs->GR_L(i)=EVM_L(vmb+VMGPRS+(i*4));
1122         }
1123         /* Clear I/O Old PSW Byte 0 */
1124         EVM_STC(0,IOOPSW);
1125         /* Issue PTLB if necessary */
1126         if(EVM_IC(APSTAT2) & CPPTLBR)
1127         {
1128             DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Purging TLB\n"));
1129             ARCH_DEP(purge_tlb)(regs);
1130             EVM_STC(EVM_IC(APSTAT2) & ~CPPTLBR,APSTAT2);
1131         }
1132 
1133         /* Update cached VMBLOK flags */
1134         EVM_STC(B_VMDSTAT,vmb+VMDSTAT);
1135         EVM_STC(B_VMRSTAT,vmb+VMRSTAT);
1136         EVM_STC(B_VMESTAT,vmb+VMESTAT);
1137         EVM_STC(B_VMPSTAT,vmb+VMPSTAT);
1138         EVM_STC(B_VMOSTAT,vmb+VMOSTAT);
1139         work_p=MADDR(vmb+VMPSW,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0); \
1140         ARCH_DEP(store_psw) (&wregs,work_p);
1141 
1142 
1143         /* Stop charging current VM Block for Supervisor time */
1144         CHARGE_STOP(vmb);
1145 
1146         /* Rest goes for problem state */
1147         SPT(vmb+VMTMOUTQ);
1148         /* Save RUNCR0, RUNCR1 & RUNPSW */
1149         /* Might be used by later CP Modules (including DMKPRV) */
1150         EVM_ST(NCR0,RUNCR0);
1151         EVM_ST(NCR1,RUNCR1);
1152         work_p=MADDR(RUNPSW,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0); \
1153         ARCH_DEP(store_psw) (&rregs,work_p);
1154         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Entry Real "));
1155         DEBUG_CPASSISTX(DISP2,display_psw(regs));
1156         ARCH_DEP(load_psw) (regs,work_p);
1157         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Now being dispatched\n",vmb));
1158         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Real "));
1159         DEBUG_CPASSISTX(DISP2,display_psw(regs));
1160         DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Virtual "));
1161         DEBUG_CPASSISTX(DISP2,display_psw(&wregs));
1162         /* TEST */
1163         ARCH_DEP(purge_tlb)(regs);
1164         SET_IC_MASK(regs);
1165         SET_AEA_MODE(regs);
1166         SET_AEA_COMMON(regs);
1167         SET_PSW_IA(regs);
1168         /* Dispatch..... */
1169         DEBUG_CPASSISTX(DISP2,display_regs(regs));
1170         DEBUG_CPASSISTX(DISP2,display_cregs(regs));
1171         return(2);      /* OK - Perform INTCHECK */
1172     }
1173     /* Nothing else to do - wait state */
1174     DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Nothing to dispatch - IDLEECPS\n"));
1175     UPD_PSW_IA(regs, EVM_L(el+24));      /* IDLEECPS */
1176     return(0);
1177 }
1178 
1179 /* DISP1 : Early tests part 2 */
1180 /*   DISP1 Checks if the user is OK to run */
1181 /*         early tests part 1 already done by DISP0 */
DEF_INST(ecpsvm_disp1)1182 DEF_INST(ecpsvm_disp1)
1183 {
1184 
1185     ECPSVM_PROLOG(DISP1);
1186     switch(ecpsvm_do_disp1(regs,effective_addr1,effective_addr2))
1187     {
1188         case 0: /* Done */
1189             CPASSIST_HIT(DISP1);
1190             return;
1191         case 1: /* No-op */
1192             break;
1193         case 2: /* Call DISP2 - INTCHECK NOT needed */
1194             switch(ecpsvm_do_disp2(regs,effective_addr1,effective_addr2))
1195             {
1196                 case 0:
1197                         CPASSIST_HIT(DISP1);
1198                         return;
1199                 case 1:
1200                         return;
1201                 case 2:
1202                         CPASSIST_HIT(DISP1);
1203                         RETURN_INTCHECK(regs);
1204                 default:
1205                         break;
1206             }
1207             return;
1208         default:
1209             return;
1210     }
1211 }
ecpsvm_int_lra(REGS * regs,VADR pgadd,RADR * raddr)1212 static int ecpsvm_int_lra(REGS *regs,VADR pgadd,RADR *raddr)
1213 {
1214     int cc;
1215     cc = ARCH_DEP(translate_addr) (pgadd , USE_PRIMARY_SPACE, regs, ACCTYPE_LRA);
1216     *raddr = regs->dat.raddr;
1217     return cc;
1218 }
1219 /* TRANBRNG/TRANLOCK Common code */
ecpsvm_tranbrng(REGS * regs,VADR cortabad,VADR pgadd,RADR * raddr)1220 static int ecpsvm_tranbrng(REGS *regs,VADR cortabad,VADR pgadd,RADR *raddr)
1221 {
1222     int cc;
1223     int corcode;
1224 #if defined(FEATURE_2K_STORAGE_KEYS)
1225     RADR pg1,pg2;
1226 #endif
1227     VADR cortab;
1228     cc=ecpsvm_int_lra(regs,pgadd,raddr);
1229     if(cc!=0)
1230     {
1231         DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Tranbring : LRA cc = %d\n"),cc));
1232         return(1);
1233     }
1234     /* Get the core table entry from the Real address */
1235     cortab=EVM_L( cortabad );
1236     cortab+=((*raddr) & 0xfff000) >> 8;
1237     corcode=EVM_IC(cortab+8);
1238     if(!(corcode & 0x08))
1239     {
1240         DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Page not shared - OK %d\n"),cc));
1241         return(0);      /* Page is NOT shared.. All OK */
1242     }
1243 #if defined(FEATURE_2K_STORAGE_KEYS)
1244     pg1=(*raddr & 0xfff000);
1245     pg2=pg1+0x800;
1246     DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Checking 2K Storage keys @"F_RADR" & "F_RADR"\n"),pg1,pg2));
1247     if((STORAGE_KEY(pg1,regs) & STORKEY_CHANGE) ||
1248             (STORAGE_KEY(pg2,regs) & STORKEY_CHANGE))
1249     {
1250 #else
1251     DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Checking 4K Storage keys @"F_RADR"\n"),*raddr));
1252     if(STORAGE_KEY(*raddr,regs) & STORKEY_CHANGE)
1253     {
1254 #endif
1255         DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Page shared and changed\n")));
1256         return(1);      /* Page shared AND changed */
1257     }
1258     DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Page shared but not changed\n")));
1259     return(0);  /* All done */
1260 }
1261 /* TRBRG : Translate a page address */
1262 /* TRBRG D1(R1,B1),D2(R2,B2) */
1263 /* 1st operand : Coretable address */
1264 /* 2nd operand : Virtual address */
1265 /* Note : CR1 Contains the relevant segment table */
1266 /*        pointers                                */
1267 /* The REAL address is resolved. If the page is flagged */
1268 /* as shared in the core table, the page is checked for */
1269 /* the change bit                                       */
1270 /* If no unusual condition is detected, control is returned */
1271 /* to the address in GPR 14. Otherwise, TRBRG is a no-op */
1272 DEF_INST(ecpsvm_tpage)
1273 {
1274     int rc;
1275     RADR raddr;
1276     ECPSVM_PROLOG(TRBRG);
1277     DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : TRANBRNG\n")));
1278     rc=ecpsvm_tranbrng(regs,effective_addr1,regs->GR_L(1),&raddr);
1279     if(rc)
1280     {
1281         DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : TRANBRNG - Back to CP\n")));
1282         return; /* Something not right : NO OP */
1283     }
1284     regs->psw.cc=0;
1285     regs->GR_L(2)=raddr;
1286     UPD_PSW_IA(regs, effective_addr2);
1287     CPASSIST_HIT(TRBRG);
1288     return;
1289 }
1290 /* TRLOK : Translate a page address and lock */
1291 /* TRLOK D1(R1,B1),D2(R2,B2) */
1292 /* See TRBRG. */
1293 /* If sucessfull, the page is also locked in the core table */
1294 DEF_INST(ecpsvm_tpage_lock)
1295 {
1296     int rc;
1297     RADR raddr;
1298     ECPSVM_PROLOG(TRLOK);
1299     DEBUG_CPASSISTX(TRLOK,logmsg(_("HHCEV300D : TRANLOCK\n")));
1300     rc=ecpsvm_tranbrng(regs,effective_addr1,regs->GR_L(1),&raddr);
1301     if(rc)
1302     {
1303         DEBUG_CPASSISTX(TRLOK,logmsg(_("HHCEV300D : TRANLOCK - Back to CP\n")));
1304         return; /* Something not right : NO OP */
1305     }
1306     /*
1307      * Lock the page in Core Table
1308      */
1309     ecpsvm_lockpage1(regs,effective_addr1,raddr);
1310     regs->psw.cc=0;
1311     regs->GR_L(2)=raddr;
1312     UPD_PSW_IA(regs, effective_addr2);
1313     CPASSIST_HIT(TRLOK);
1314     return;
1315 }
1316 /* VIST : Not supported */
1317 DEF_INST(ecpsvm_inval_segtab)
1318 {
1319     ECPSVM_PROLOG(VIST);
1320 }
1321 /* VIPT : Not supported */
1322 DEF_INST(ecpsvm_inval_ptable)
1323 {
1324     ECPSVM_PROLOG(VIPT);
1325 }
1326 /* DFCCW : Not Supported */
1327 DEF_INST(ecpsvm_decode_first_ccw)
1328 {
1329     ECPSVM_PROLOG(DFCCW);
1330 }
1331 
1332 /* DISP0 Utility functions */
1333 
1334 /* DMKDSP - INCPROBT */
1335 
1336 static int ecpsvm_disp_incprobt(REGS *regs,VADR vmb)
1337 {
1338     U64 tspent;
1339     U64 DW_VMTMOUTQ;
1340     U64 DW_PROBSTRT;
1341     U64 DW_PROBTIME;
1342 
1343     DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Entry : VMBLOK @ %8.8X\n",vmb));
1344     DW_VMTMOUTQ=EVM_LD(vmb+VMTMOUTQ);
1345     DW_PROBSTRT=EVM_LD(PROBSTRT);
1346     DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Entry : VMTMOUTQ = %16.16" I64_FMT "x\n",DW_VMTMOUTQ));
1347     DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Entry : PROBSTRT = %16.16" I64_FMT "x\n",DW_PROBSTRT));
1348     if(DW_VMTMOUTQ==DW_PROBSTRT)
1349     {
1350         DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Already performed"));
1351         return(2);      /* continue */
1352     }
1353     tspent=DW_PROBSTRT-DW_VMTMOUTQ;
1354     DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT TSPENT = %16.16" I64_FMT "x\n",tspent));
1355     DW_PROBTIME=EVM_LD(PROBTIME);
1356     DW_PROBTIME-=tspent;
1357     EVM_STD(DW_PROBTIME,PROBTIME);
1358     DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT NEW PROBTIME = %16.16" I64_FMT "x\n",DW_PROBTIME));
1359     return(2);
1360 }
1361 
1362 /* DMKDSP
1363 RUNTIME
1364 */
1365 
1366 static int ecpsvm_disp_runtime(REGS *regs,VADR *vmb_p,VADR dlist,VADR exitlist)
1367 {
1368     U64 DW_VMTTIME;
1369     U64 DW_VMTMINQ;
1370     BYTE B_VMDSTAT;
1371     BYTE B_VMTLEVEL;
1372     BYTE B_VMMCR6;
1373     U32  F_QUANTUM;
1374     U32  F_QUANTUMR;
1375     U32  F_ITIMER;
1376     int cc;
1377     RADR raddr;
1378     VADR tmraddr;
1379     U32  oldtimer,newtimer;
1380     VADR vmb;
1381     VADR runu;
1382 
1383     vmb=*vmb_p;
1384     DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME Entry : VMBLOK @ %8.8X\n",vmb));
1385     runu=EVM_L(RUNUSER);
1386     /* BAL RUNTIME Processing */
1387     EVM_STC(CPEX+CPSUPER,CPSTATUS);
1388     CHARGE_STOP(vmb);
1389     if(vmb!=runu)
1390     {
1391         DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME Switching to RUNUSER VMBLOK @ %8.8X\n",runu));
1392         CHARGE_SWITCH(vmb,runu);    /* Charge RUNUSER */
1393         F_ITIMER=EVM_L(QUANTUMR);
1394         *vmb_p=vmb;
1395     }
1396     else
1397     {
1398         F_ITIMER=EVM_L(INTTIMER);
1399     }
1400     DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : VMBLOK @ %8.8X\n",vmb));
1401     /* vmb is now RUNUSER */
1402     /* Check if time slice is over */
1403     if(F_ITIMER & 0x80000000)
1404     {
1405         B_VMDSTAT=EVM_IC(vmb+VMDSTAT);
1406         B_VMDSTAT&=~VMDSP;
1407         B_VMDSTAT|=VMTSEND;
1408         EVM_STC(B_VMDSTAT,vmb+VMDSTAT);
1409     }
1410     /* Check if still eligible for current run Q */
1411     DW_VMTTIME=EVM_LD(vmb+VMTTIME);
1412     DW_VMTMINQ=EVM_LD(vmb+VMTMINQ);
1413     /* Check 1st 5 bytes */
1414     /*2017-03-27 added equality check*/
1415     if((DW_VMTTIME & 0xffffffffff000000ULL) <= (DW_VMTMINQ & 0xffffffffff000000ULL))
1416     {
1417         B_VMDSTAT=EVM_IC(vmb+VMDSTAT);
1418         B_VMDSTAT&=~VMDSP;
1419         B_VMDSTAT|=VMQSEND;
1420         EVM_STC(B_VMDSTAT,vmb+VMDSTAT);
1421     }
1422     ecpsvm_disp_incprobt(regs,vmb);
1423     F_QUANTUM=EVM_L(QUANTUM);
1424     EVM_ST(F_ITIMER,QUANTUM);
1425     /* Check if Virtual Timer assist is active */
1426     B_VMMCR6=EVM_IC(vmb+VMMCR6);
1427     if(B_VMMCR6 & 0x01)      /* Virtual Timer Flag */
1428     {
1429         DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - VTIMER Assist active\n"));
1430         return(2);      /* End of "RUNTIME" here */
1431     }
1432     /* Check SET TIMER ON or SET TIMER REAL */
1433     B_VMTLEVEL=EVM_IC(vmb+VMTLEVEL);
1434     if(!(B_VMTLEVEL & (VMTON | VMRON)))
1435     {
1436         DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - SET TIMER OFF\n"));
1437         return(2);
1438     }
1439     /* Update virtual interval timer */
1440     F_QUANTUMR=EVM_L(QUANTUMR);
1441     F_QUANTUM-=F_QUANTUMR;
1442     if(F_QUANTUM & 0x80000000)
1443     {
1444         /* Abend condition detected during virtual time update - exit at +32 */
1445         DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Bad ITIMER - Taking Exist #32\n"));
1446         UPD_PSW_IA(regs, EVM_L(exitlist+32));
1447         return(0);
1448     }
1449     /* Load CR1 with the vmblock's VMSEG */
1450     regs->CR_L(1)=EVM_L(vmb+VMSEG);
1451     /* Do LRA - Don't access the page directly yet - Could yield a Paging fault */
1452     cc = ecpsvm_int_lra(regs,INTTIMER,&raddr);
1453     if(cc!=0)
1454     {
1455         /* Update VMTIMER instead */
1456         tmraddr=vmb+VMTIMER;
1457     }
1458     else
1459     {
1460         tmraddr=(VADR)raddr;
1461     }
1462     oldtimer=EVM_L(tmraddr);
1463     newtimer=oldtimer-F_QUANTUM;
1464     EVM_ST(newtimer,tmraddr);
1465     if((newtimer & 0x80000000) != (oldtimer & 0x80000000))
1466     {
1467         /* Indicate XINT to be generated (exit + 8) */
1468         /* Setup a few regs 1st */
1469         regs->GR_L(3)=0;
1470         regs->GR_L(4)=0x00800080;
1471         regs->GR_L(9)=EVM_L(dlist+4);
1472         regs->GR_L(11)=vmb;
1473         /*2017-03-27,ensure VMDSP is off*/
1474         B_VMDSTAT=EVM_IC(vmb+VMDSTAT);
1475         B_VMDSTAT&=~VMDSP;
1476         EVM_STC(B_VMDSTAT,vmb+VMDSTAT);
1477         /* end of 2017-03-27 */
1478         UPD_PSW_IA(regs, EVM_L(exitlist+8));
1479         DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - Taking exit #8\n"));
1480         return(0);
1481     }
1482     /* Return - Continue DISP0 Processing */
1483     DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - ITIMER Updated\n"));
1484     return(2);
1485 }
1486 
1487 /* DISP0 : Operand 1 : DISP0 Data list, Operand 2 : DISP0 Exit list */
1488 /*         R11 : User to dispatch                                   */
1489 DEF_INST(ecpsvm_dispatch_main)
1490 {
1491     VADR dlist;
1492     VADR elist;
1493     VADR vmb;
1494     /* PSA Fetched Values */
1495     BYTE B_CPSTATUS;
1496     BYTE B_VMDSTAT;
1497     BYTE B_VMPSTAT;
1498     BYTE B_VMRSTAT;
1499     BYTE B_VMPEND;
1500     BYTE B_VMESTAT;
1501 
1502     VADR F_VMPXINT;
1503     VADR OXINT; /* Back chain ptr for exit 20 */
1504     U32  F_VMPSWHI;
1505     U32  F_VMVCR0;
1506     U32  F_VMIOINT;
1507     U32 F_VMVCR2;
1508     U32 DISPCNT;
1509 
1510     U16  H_XINTMASK;
1511 
1512     U32 iomask;
1513     BYTE extendmsk;     /* Extended I/O mask */
1514 
1515     ECPSVM_PROLOG(DISP0);
1516 
1517     dlist=effective_addr1;
1518     elist=effective_addr2;
1519     vmb=regs->GR_L(11);
1520     DISPCNT=EVM_L(dlist);
1521     DISPCNT++;
1522     /* Question #1 : Are we currently running a user */
1523     B_CPSTATUS=EVM_IC(CPSTATUS);
1524     if((B_CPSTATUS & CPRUN))
1525     {
1526         DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CPRUN On\n"));
1527         switch(ecpsvm_disp_runtime(regs,&vmb,dlist,elist))
1528         {
1529             case 0: /* Exit taken - success */
1530             EVM_ST(DISPCNT,dlist);
1531             CPASSIST_HIT(DISP0);
1532             return;
1533             case 1: /* no-op DISP0 */
1534             return;
1535             default: /* Continue processing */
1536             break;
1537         }
1538         /* Load VMDSTAT */
1539         B_VMDSTAT=EVM_IC(vmb+VMDSTAT);
1540         /* Check if I/O Old PSW has tranlation on */
1541         if(regs->mainstor[0x38] & 0x04)
1542         {
1543             DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : I/O Old as XLATE on\n"));
1544             /* Yes - I/O Interrupt while running a USER */
1545             if(B_VMDSTAT & VMDSP)
1546             {
1547                 DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VMDSP on in VMBLOK - Clean status (Exit #36)\n"));
1548                 /* Clean status - Do exit 36 */
1549                 regs->GR_L(11)=vmb;
1550                 UPD_PSW_IA(regs, EVM_L(elist+36));
1551                 EVM_ST(DISPCNT,dlist);
1552                 CPASSIST_HIT(DISP0);
1553                 return;
1554             }
1555         }
1556     }
1557     else
1558     {
1559         DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CPRUN Off\n"));
1560         /* Check if was in Wait State */
1561         if(B_CPSTATUS & CPWAIT)
1562         {
1563             DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CPWAIT On : Exit #4\n"));
1564             /* Take exit #4 : Coming out of wait state */
1565             /* DMKDSPC3 */
1566             /* No need to update R11 */
1567             CPASSIST_HIT(DISP0);
1568             UPD_PSW_IA(regs, EVM_L(elist+4));
1569             EVM_ST(DISPCNT,dlist);
1570             return;
1571         }
1572     }
1573     /* VMB is now either original GPR11 or RUNUSER */
1574     /* DMKDSP - UNSTACK */
1575     DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : At UNSTACK : VMBLOK = %8.8X\n",vmb));
1576     B_VMRSTAT=EVM_IC(vmb+VMRSTAT);
1577     if(B_VMRSTAT & VMCPWAIT)
1578     {
1579         DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VMRSTAT VMCPWAIT On (%2.2X) - Taking exit #12\n",B_VMRSTAT));
1580         /* Take Exit 12 */
1581         regs->GR_L(11)=vmb;
1582         UPD_PSW_IA(regs, EVM_L(elist+12));
1583         CPASSIST_HIT(DISP0);
1584         EVM_ST(DISPCNT,dlist);
1585         return;
1586     }
1587     /* Check for PER/PPF (CKPEND) */
1588     B_VMPEND=EVM_IC(vmb+VMPEND);
1589     if(B_VMPEND & (VMPERPND | VMPGPND))
1590     {
1591         DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : PER/PPF Pending - Taking exit #16\n"));
1592         /* Take Exit 16 */
1593         regs->GR_L(11)=vmb;
1594         UPD_PSW_IA(regs, EVM_L(elist+16));
1595         CPASSIST_HIT(DISP0);
1596         EVM_ST(DISPCNT,dlist);
1597         return;
1598     }
1599     /* Now, check if we should unstack an external int */
1600     /* 1st check if VMPXINT is NULL */
1601     F_VMPSWHI=EVM_L(vmb+VMPSW);     /* Load top of virt PSW - Will need it */
1602     B_VMPSTAT=EVM_IC(vmb+VMPSTAT);   /* Will need VMPSTAT for I/O ints too */
1603     F_VMPXINT=EVM_L(vmb+VMPXINT);
1604     DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : Checking for EXT; Base VMPXINT=%8.8X\n",F_VMPXINT));
1605     /* This is DMKDSP - CKEXT */
1606     if(F_VMPXINT!=0)
1607     {
1608         DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VPSW HI = %8.8X\n",F_VMPSWHI));
1609         OXINT=vmb+VMPXINT;
1610         /* Check if Virtual PSW enabled for Externals */
1611         /* (works in both BC & EC modes) */
1612         if(F_VMPSWHI & 0x01000000)
1613         {
1614             DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : PSW Enabled for EXT\n"));
1615             /* Use VMVCR0 or CR0 in ECBLOK */
1616             F_VMVCR0=EVM_L(vmb+VMVCR0);     /* CR0 or ECBLOK Address */
1617             if(B_VMPSTAT & VMV370R) /* SET ECMODE ON ?? */
1618             {
1619                 F_VMVCR0=EVM_L(F_VMVCR0+0); /* EXTCR0 at disp +0 in ECBLOK */
1620             }
1621             DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CR0 = %8.8X\n",F_VMVCR0));
1622             /* scan the XINTBLOKS for a mask match */
1623             /* Save OXINT in the loop for exit 20  */
1624             for(;F_VMPXINT;OXINT=F_VMPXINT,F_VMPXINT=EVM_L(F_VMPXINT))      /* XINTNEXT @ +0 in XINTBLOK */
1625             {
1626                 H_XINTMASK=EVM_LH(F_VMPXINT+10);    /* Get interrupt subclass in XINTBLOK */
1627                 DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : XINTMASK =  %4.4X\n",H_XINTMASK));
1628                 H_XINTMASK &= F_VMVCR0;
1629                 if(H_XINTMASK)           /* Check against CR0 (External subclass mask) */
1630                 {
1631                     DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : EXT Hit - Taking exit #20\n"));
1632                     /* Enabled for this external */
1633                     /* Take exit 20 */
1634                     regs->GR_L(4)=H_XINTMASK;            /* Enabled subclass bits */
1635                     regs->GR_L(5)=OXINT;                 /* XINTBLOK Back pointer (or VMPXINT) */
1636                     regs->GR_L(6)=F_VMPXINT;             /* Current XINTBLOK */
1637                     regs->GR_L(11)=vmb;                  /* RUNUSER */
1638                     UPD_PSW_IA(regs, EVM_L(elist+20));   /* Exit +20 */
1639                     EVM_ST(DISPCNT,dlist);
1640                     CPASSIST_HIT(DISP0);
1641                     return;
1642                 }
1643             }
1644         }
1645     }
1646     /* After CKEXT : No external pending/reflectable */
1647 
1648     /* This is DMKDSP UNSTIO */
1649     /* Check for pending I/O Interrupt */
1650 
1651     /* Load PIM */
1652     F_VMIOINT=EVM_LH(vmb+VMIOINT);
1653     DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : Checking for I/O; VMIOINT=%8.8X\n",F_VMIOINT));
1654     if(F_VMIOINT!=0)        /* If anything in the pipe */
1655     {
1656         F_VMIOINT <<=16;    /* Put IOINT mask in bits 0-15 */
1657         /* Is V-PSW in EC Mode ? */
1658         iomask=0;
1659         extendmsk=0;
1660         B_VMESTAT=EVM_L(VMESTAT);
1661         if(B_VMESTAT & VMEXTCM)     /* Implies VMV370R on */
1662         {
1663             /* Check I/O bit */
1664             if(F_VMPSWHI & 0x02000000)
1665             {
1666                 iomask=0;
1667                 extendmsk=1;
1668             }
1669         }
1670         else
1671         {
1672             /* BC Mode PSW */
1673             /* Isolate channel masks for channels 0-5 */
1674             iomask=F_VMPSWHI & 0xfc000000;
1675             if(B_VMPSTAT & VMV370R) /* SET ECMODE ON ? */
1676             {
1677                 if(F_VMPSWHI & 0x02000000)
1678                 {
1679                     extendmsk=1;
1680                 }
1681             }
1682         }
1683         if(extendmsk)
1684         {
1685             F_VMVCR2=EVM_L(vmb+VMECEXT);
1686             F_VMVCR2=EVM_L(F_VMVCR2+8);
1687             iomask |= F_VMVCR2;
1688         }
1689         if(iomask & 0xffff0000)
1690         {
1691             F_VMIOINT&=iomask;
1692             if(F_VMIOINT)
1693             {
1694                 DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : I/O Hit - Taking exit #24\n"));
1695                 /* Take Exit 24 */
1696                 regs->GR_L(7)=F_VMIOINT;
1697                 regs->GR_L(11)=vmb;
1698                 UPD_PSW_IA(regs, EVM_L(elist+24));   /* Exit +24 */
1699                 EVM_ST(DISPCNT,dlist);
1700                 CPASSIST_HIT(DISP0);
1701                 return;
1702             }
1703         }
1704     }
1705     /* DMKDSP - CKWAIT */
1706     /* Clear Wait / Idle bits in VMRSTAT */
1707     B_VMRSTAT=EVM_IC(vmb+VMRSTAT);
1708     B_VMRSTAT &= ~(VMPSWAIT | VMIDLE);
1709     EVM_STC(B_VMRSTAT,vmb+VMRSTAT);
1710     if(F_VMPSWHI & 0x00020000)
1711     {
1712         DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VWAIT - Taking exit #28\n"));
1713         /* Take exit 28  */
1714         /* 2017-03-27 Set VMPSWAIT */
1715         B_VMRSTAT |= VMPSWAIT;
1716         EVM_STC(B_VMRSTAT,vmb+VMRSTAT);
1717         /* end of 2017-03-27 */
1718         regs->GR_L(11)=vmb;
1719         UPD_PSW_IA(regs, EVM_L(elist+28));   /* Exit +28 */
1720         CPASSIST_HIT(DISP0);
1721         EVM_ST(DISPCNT,dlist);
1722         return;
1723     }
1724     /* Take exit 0 (DISPATCH) */
1725     DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : DISPATCH - Taking exit #0\n"));
1726     regs->GR_L(11)=vmb;
1727     UPD_PSW_IA(regs, EVM_L(elist+0));   /* Exit +0 */
1728     CPASSIST_HIT(DISP0);
1729     EVM_ST(DISPCNT,dlist);
1730     return;
1731 }
1732 
1733 
1734 /******************************************************/
1735 /* SCNRU Instruction : Scan Real Unit                 */
1736 /* Invoked by DMKSCN                                  */
1737 /* E60D                                               */
1738 /* SCNRU D1(R1,B1),D2(R2,B2)                          */
1739 /*                                                    */
1740 /* Operations                                         */
1741 /* The Device Address specified in operand 1 is       */
1742 /* the real device address for which control block    */
1743 /* addresses are to be returned. The storage area     */
1744 /* designated as the 2nd operand is a list of 4       */
1745 /* consecutive fullword (note : the 2nd operand is    */
1746 /* treated as a Real Address, regardless of any       */
1747 /* translation mode that may be in effect)            */
1748 /* +--------------------+-------------------+         */
1749 /* | CHNLINDEX          | RCHTABLE          |         */
1750 /* +--------------------+-------------------+         */
1751 /* | RCUTABLE           | RDVTABLE          |         */
1752 /* +--------------------+-------------------+         */
1753 /* CHNLINDEX is an array of 16 halfwords, each        */
1754 /* representing the offset of the target's device     */
1755 /* channel's RCHBLOCK. If the channel is not defined  */
1756 /* in the RIO table, the index has bit 0, byte 0 set  */
1757 /* to 1                                               */
1758 /*                                                    */
1759 /* The RCHBLOK has at offset +X'20' a table of        */
1760 /* 32 possible control unit indices                   */
1761 /* the device's address bit 8 to 12 are used to fetch */
1762 /* the index specified at the table. If it has        */
1763 /* bit 0 byte 0 set, then the same operation is       */
1764 /* attempted with bits 8 to 11                        */
1765 /* The RCUBLOK then fetched from RCUTABLE + the index */
1766 /* fetched from the RCHBLOK has a DEVICE index table  */
1767 /* at offset +X'28' which can be fetched by using     */
1768 /* bits 5-7                                           */
1769 /* If the RCUBLOK designates an alternate control     */
1770 /* unit block, (Offset +X'5' bit 1 set), then         */
1771 /* the primary RCUBLOK is fetched from offset X'10'   */
1772 /*                                                    */
1773 /* If no RCHBLOK is found, R6,R7 and R8 contain -1    */
1774 /* and Condition Code 3 is set                        */
1775 /*                                                    */
1776 /* if no RCUBLOK is found, R6 contains the RCHBLOK,   */
1777 /* R7 and R8 contain -1, and Condition Code 2 is set  */
1778 /*                                                    */
1779 /* if no RDVBLOK is found, R6 contains the RCHBLOK,   */
1780 /* R7 contains the RCUBLOK and R8 contains -1, and    */
1781 /* condition code 1 is set                            */
1782 /*                                                    */
1783 /* If all 3 control blocks are found, R6 contains the */
1784 /* the RCHBLOK, R7 Contains the RCUBLOK and R8 cont-  */
1785 /* ains the RDVBLOK. Condition code 0 is set          */
1786 /*                                                    */
1787 /* If the instruction is sucesfull, control is        */
1788 /* returned at the address specified by GPR14.        */
1789 /* Otherwise, the next sequential instruction is      */
1790 /* executed, and no GPR or condition code is changed. */
1791 /*                                                    */
1792 /* Exceptions :                                       */
1793 /*       Operation Exception : ECPS:VM Disabled       */
1794 /*       Priviledged Exception : PSW in problem state */
1795 /*                                                    */
1796 /* Note : no access exception is generated for        */
1797 /*        the second operand.                         */
1798 /*                                                    */
1799 /* Note : as of yet, for any other situation than     */
1800 /*        finding all 3 control blocks, SCNRU acts    */
1801 /*        as a NO-OP                                  */
1802 /******************************************************/
1803 DEF_INST(ecpsvm_locate_rblock)
1804 {
1805     U32 chix;           /* offset of RCH in RCH Array */
1806     U32 cuix;           /* Offset of RCU in RCU Array */
1807     U32 dvix;           /* Offset of RDV in RDV Array */
1808     VADR rchixtbl;      /* RCH Index Table */
1809     VADR rchtbl;        /* RCH Array */
1810     VADR rcutbl;        /* RCU Array */
1811     VADR rdvtbl;        /* RDV Array */
1812     VADR arioct;        /* Data list for SCNRU */
1813 
1814     VADR rchblk;        /* Effective RCHBLOK Address */
1815     VADR rcublk;        /* Effective RCUBLOK Address */
1816     VADR rdvblk;        /* Effective RDVBLOK Address */
1817     U16 rdev;
1818 
1819     ECPSVM_PROLOG(SCNRU);
1820 
1821     /* Obtain the Device address */
1822     rdev=(effective_addr1 & 0xfff);
1823     /* And the DMKRIO tables addresses */
1824     arioct=effective_addr2;
1825 
1826     DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU called; RDEV=%4.4X ARIOCT=%6.6X\n"),effective_addr1,arioct));
1827 
1828     /* Get the Channel Index Table */
1829     rchixtbl= EVM_L(effective_addr2);
1830 
1831     /* Obtain the RCH offset */
1832     chix=EVM_LH(rchixtbl+((rdev & 0xf00) >> 7));
1833 
1834     DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RCH IX = %x\n"),chix));
1835 
1836     /* Check if Bit 0 set (no RCH) */
1837     if(chix & 0x8000)
1838     {
1839         // logmsg(_("HHCEV300D : ECPS:VM SCNRU : NO CHANNEL\n"));
1840         /*
1841         regs->GR_L(6)=~0;
1842         regs->GR_L(7)=~0;
1843         regs->GR_L(8)=~0;
1844         UPD_PSW_IA(regs, regs->GR_L(14));
1845         regs->psw.cc=1;
1846         */
1847         /* Right now, let CP handle the case */
1848         return;
1849     }
1850 
1851     /* Obtain the RCH Table pointer */
1852     rchtbl=EVM_L(arioct+4);
1853 
1854     /* Add the RCH Index offset */
1855     rchblk=rchtbl+chix;
1856 
1857     /* Try to obtain RCU index with bits 8-12 of the device */
1858     cuix=EVM_LH(rchblk+0x20+((rdev & 0xf8)>>2));
1859     if(cuix & 0x8000)
1860     {
1861         /* Try with bits 8-11 */
1862         cuix=EVM_LH(rchblk+0x20+((rdev & 0xf0)>>2));
1863         if(cuix & 0x8000)
1864         {
1865             // logmsg(_("HHCEV300D : ECPS:VM SCNRU : NO CONTROL UNIT\n"));
1866             /*
1867             regs->GR_L(6)=rchblk;
1868             regs->GR_L(7)=~0;
1869             regs->GR_L(8)=~0;
1870             UPD_PSW_IA(regs, regs->GR_L(14));
1871             regs->psw.cc=2;
1872             */
1873             return;
1874         }
1875     }
1876     DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RCU IX = %x\n"),cuix));
1877     rcutbl=EVM_L(arioct+8);
1878     rcublk=rcutbl+cuix;
1879     dvix=EVM_LH(rcublk+0x28+((rdev & 0x00f)<<1));
1880     if(EVM_IC(rcublk+5)&0x40)
1881     {
1882         rcublk=EVM_L(rcublk+0x10);
1883     }
1884     if(dvix & 0x8000)
1885     {
1886         // logmsg(_("HHCEV300D : ECPS:VM SCNRU : NO RDEVBLOK\n"));
1887         /*
1888         regs->GR_L(6)=rchblk;
1889         regs->GR_L(7)=rcublk;
1890         regs->GR_L(8)=~0;
1891         UPD_PSW_IA(regs, regs->GR_L(14));
1892         regs->psw.cc=3;
1893         */
1894         return;
1895     }
1896     DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RDV IX = %x\n"),dvix));
1897     dvix<<=3;
1898     rdvtbl=EVM_L(arioct+12);
1899     rdvblk=rdvtbl+dvix;
1900     DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RCH = %6.6X, RCU = %6.6X, RDV = %6.6X\n"),rchblk,rcublk,rdvblk));
1901     regs->GR_L(6)=rchblk;
1902     regs->GR_L(7)=rcublk;
1903     regs->GR_L(8)=rdvblk;
1904     regs->psw.cc=0;
1905     regs->GR_L(15)=0;
1906     BR14;
1907     CPASSIST_HIT(SCNRU);
1908 }
1909 /* CCWGN : Not supported */
1910 DEF_INST(ecpsvm_comm_ccwproc)
1911 {
1912     ECPSVM_PROLOG(CCWGN);
1913 }
1914 /* UXCCW : Not supported */
1915 DEF_INST(ecpsvm_unxlate_ccw)
1916 {
1917     ECPSVM_PROLOG(UXCCW);
1918 }
1919 /* DISP2 : Not supported */
1920 DEF_INST(ecpsvm_disp2)
1921 {
1922     ECPSVM_PROLOG(DISP2);
1923     switch(ecpsvm_do_disp2(regs,effective_addr1,effective_addr2))
1924     {
1925         case 0: /* Done */
1926             CPASSIST_HIT(DISP2);
1927             return;
1928         case 1: /* No-op */
1929             return;
1930         case 2: /* Done */
1931             CPASSIST_HIT(DISP2);
1932             RETURN_INTCHECK(regs);
1933     }
1934     return;
1935 }
1936 /* STEVL : Store ECPS:VM support level */
1937 /* STEVL D1(R1,B1),D2(R2,B2) */
1938 /* 1st operand : Fullword address in which to store ECPS:VM Support level */
1939 /* 2nd operand : ignored */
1940 DEF_INST(ecpsvm_store_level)
1941 {
1942     ECPSVM_PROLOG(STEVL);
1943     EVM_ST(sysblk.ecpsvm.level,effective_addr1);
1944     DEBUG_CPASSISTX(STEVL,logmsg(_("HHCEV300D : ECPS:VM STORE LEVEL %d called\n"),sysblk.ecpsvm.level));
1945     CPASSIST_HIT(STEVL);
1946 }
1947 /* LCSPG : Locate Changed Shared Page */
1948 /* LCSPG : Not supported */
1949 DEF_INST(ecpsvm_loc_chgshrpg)
1950 {
1951     ECPSVM_PROLOG(LCSPG);
1952 }
1953 /*************************************************************/
1954 /* FREEX : Allocate CP Storage Extended                      */
1955 /* FREEX B1(R1,B1),D2(R2,B2)                                 */
1956 /* 1st operand : Address of FREEX Parameter list             */
1957 /*               +0 : Maxsize = Max number of DW allocatable */
1958 /*                              with FREEX                   */
1959 /*               +4- : Subpool index table                   */
1960 /* 2nd operand : Subpool table (indexed)                     */
1961 /* GPR 0 : Number of DWs to allocate                         */
1962 /*                                                           */
1963 /* Each allocatable block is forward chained                 */
1964 /* if the subpool is empty, return to caller                 */
1965 /* if the subpool has an entry, allocate from the subpool    */
1966 /* and save the next block address as the subpool chain head */
1967 /* return allocated block in GPR1. return at address in GPR14*/
1968 /* if allocation succeeded                                   */
1969 /* if allocate fails, return at next sequential instruction  */
1970 /*************************************************************/
1971 DEF_INST(ecpsvm_extended_freex)
1972 {
1973     U32 maxdw;
1974     U32 numdw;
1975     U32 maxsztbl;
1976     U32 spixtbl;
1977     BYTE spix;
1978     U32 freeblock;
1979     U32 nextblk;
1980     ECPSVM_PROLOG(FREEX);
1981     numdw=regs->GR_L(0);
1982     spixtbl=effective_addr2;
1983     maxsztbl=effective_addr1;
1984     DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : ECPS:VM FREEX DW = %4.4X\n"),numdw));
1985     if(numdw==0)
1986     {
1987         return;
1988     }
1989     DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : MAXSIZE ADDR = %6.6X, SUBPOOL INDEX TABLE = %6.6X\n"),maxsztbl,spixtbl));
1990     /* E1 = @ of MAXSIZE (maximum # of DW allocatable by FREEX from subpools) */
1991     /*      followed by subpool pointers                                      */
1992     /* E2 = @ of subpool indices                                              */
1993     maxdw=EVM_L(maxsztbl);
1994     if(regs->GR_L(0)>maxdw)
1995     {
1996         DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : FREEX request beyond subpool capacity\n")));
1997         return;
1998     }
1999     /* Fetch subpool index */
2000     spix=EVM_IC(spixtbl+numdw);
2001     DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : Subpool index = %X\n"),spix));
2002     /* Fetch value */
2003     freeblock=EVM_L(maxsztbl+4+spix);
2004     DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : Value in subpool table = %6.6X\n"),freeblock));
2005     if(freeblock==0)
2006     {
2007         /* Can't fullfill request here */
2008         return;
2009     }
2010     nextblk=EVM_L(freeblock);
2011     EVM_ST(nextblk,maxsztbl+4+spix);
2012     DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : New Value in subpool table = %6.6X\n"),nextblk));
2013     regs->GR_L(1)=freeblock;
2014     regs->psw.cc=0;
2015     BR14;
2016     CPASSIST_HIT(FREEX);
2017     return;
2018 }
2019 /*************************************************************/
2020 /* FRETX : Return CP Free storage                            */
2021 /* FRETX D1(R1,B1),R2(D2,B2)                                 */
2022 /* 1st operand : Max DW for subpool free/fret                */
2023 /* 2nd Operand : FRET PLIST                                  */
2024 /*               +0 Coretable address                        */
2025 /*               +4 CL4'FREE'                                */
2026 /*               +8 Maxsize (same as operand 1)              */
2027 /*               +12 Subpool Table Index                     */
2028 /* The block is checked VS the core table to check if it     */
2029 /* is eligible to be returned to the subpool chains          */
2030 /* If it is, then it is returned. Control is returned at     */
2031 /* the address in GPR 14. Otherwise, if anything cannot      */
2032 /* be resolved, control is returned at the next sequential   */
2033 /* Instruction                                               */
2034 /*************************************************************/
2035 int ecpsvm_do_fretx(REGS *regs,VADR block,U16 numdw,VADR maxsztbl,VADR fretl)
2036 {
2037     U32 cortbl;
2038     U32 maxdw;
2039     U32 cortbe; /* Core table Page entry for fretted block */
2040     U32 prevblk;
2041     BYTE spix;
2042     DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : X fretx called AREA=%6.6X, DW=%4.4X\n"),regs->GR_L(1),regs->GR_L(0)));
2043     if(numdw==0)
2044     {
2045         DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : DWORDS = 0\n")));
2046         return(1);
2047     }
2048     maxdw=EVM_L(maxsztbl);
2049     if(numdw>maxdw)
2050     {
2051         DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : DWORDS = %d > MAXDW %d\n"),numdw,maxdw));
2052         return(1);
2053     }
2054     cortbl=EVM_L(fretl);
2055     cortbe=cortbl+((block & 0xfff000)>>8);
2056     if(EVM_L(cortbe)!=EVM_L(fretl+4))
2057     {
2058         DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : Area not in Core Free area\n")));
2059         return(1);
2060     }
2061     if(EVM_IC(cortbe+8)!=0x02)
2062     {
2063         DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : Area flag != 0x02\n")));
2064         return(1);
2065     }
2066     spix=EVM_IC(fretl+11+numdw);
2067     prevblk=EVM_L(maxsztbl+4+spix);
2068     if(prevblk==block)
2069     {
2070         DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : fretted block already on subpool chain\n")));
2071         return(1);
2072     }
2073     EVM_ST(block,maxsztbl+4+spix);
2074     EVM_ST(prevblk,block);
2075     return(0);
2076 }
2077 DEF_INST(ecpsvm_extended_fretx)
2078 {
2079     U32 fretl;
2080     U32 maxsztbl;
2081     U32 numdw;
2082     U32 block;
2083 
2084     ECPSVM_PROLOG(FRETX);
2085 
2086     numdw=regs->GR_L(0);
2087     block=regs->GR_L(1) & ADDRESS_MAXWRAP(regs);
2088     maxsztbl=effective_addr1 & ADDRESS_MAXWRAP(regs);
2089     fretl=effective_addr2 & ADDRESS_MAXWRAP(regs);
2090     if(ecpsvm_do_fretx(regs,block,numdw,maxsztbl,fretl)==0)
2091     {
2092         BR14;
2093         CPASSIST_HIT(FRETX);
2094     }
2095     return;
2096 }
2097 DEF_INST(ecpsvm_prefmach_assist)
2098 {
2099     ECPSVM_PROLOG(PMASS);
2100 }
2101 
2102 /**********************************/
2103 /* VM ASSISTS                     */
2104 /**********************************/
2105 
2106 /******************************************************************/
2107 /* LPSW/SSM/STxSM :                                               */
2108 /* Not sure about the current processing ..                       */
2109 /* *MAYBE* we need to invoke DMKDSPCH when the newly loaded PSW   */
2110 /* does not need further checking. Now.. I wonder what the point  */
2111 /* is to return to CP anyway, as we have entirelly validated the  */
2112 /* new PSW (i.e. for most of it, this is essentially a BRANCH     */
2113 /* However...                                                     */
2114 /* Maybe we should call DMKDSPCH (from the DMKPRVMA list)         */
2115 /* only if re-enabling bits (and no Int pending)                  */
2116 /*                                                                */
2117 /* For the time being, we do THIS :                               */
2118 /* If the new PSW 'disables' bits or enables bit but MICPEND=0    */
2119 /* we just update the VPSW and continue                           */
2120 /* Same for LPSW.. But we also update the IA                      */
2121 /* If we encounter ANY issue, we just return to caller (which will*/
2122 /* generate a PRIVOP) thus invoking CP like for non-EVMA          */
2123 /******************************************************************/
2124 
2125 /******************************************************************/
2126 /* Check psw Transition validity                                  */
2127 /******************************************************************/
2128 /* NOTE : oldr/newr Only have the PSW field valid (the rest is not initialised) */
2129 int     ecpsvm_check_pswtrans(REGS *regs,ECPSVM_MICBLOK *micblok, BYTE micpend, REGS *oldr, REGS *newr)
2130 {
2131     UNREFERENCED(micblok);
2132     UNREFERENCED(regs);
2133 
2134     SET_PSW_IA(newr);
2135     SET_PSW_IA(oldr);
2136 
2137     /* Check for a switch from BC->EC or EC->BC */
2138     if(ECMODE(&oldr->psw)!=ECMODE(&newr->psw))
2139     {
2140         DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New and Old PSW have a EC/BC transition\n")));
2141         return(1);
2142     }
2143     /* Check if PER or DAT is being changed */
2144     if(ECMODE(&newr->psw))
2145     {
2146         if((newr->psw.sysmask & 0x44) != (oldr->psw.sysmask & 0x44))
2147         {
2148             DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW Enables DAT or PER\n")));
2149             return(1);
2150         }
2151     }
2152     /* Check if a Virtual interrupt is pending and new interrupts are being enabled */
2153     if(micpend & 0x80)
2154     {
2155         if(ECMODE(&newr->psw))
2156         {
2157             if(((~oldr->psw.sysmask) & 0x03) & newr->psw.sysmask)
2158             {
2159                 DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW Enables interrupts and MICPEND (EC)\n")));
2160                 return(1);
2161             }
2162         }
2163         else
2164         {
2165             if(~oldr->psw.sysmask & newr->psw.sysmask)
2166             {
2167                 DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW Enables interrupts and MICPEND (BC)\n")));
2168                 return(1);
2169             }
2170         }
2171     }
2172     if(WAITSTATE(&newr->psw))
2173     {
2174         DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW is a WAIT PSW\n")));
2175         return(1);
2176     }
2177     if(ECMODE(&newr->psw))
2178     {
2179         if(newr->psw.sysmask & 0xb8)
2180         {
2181             DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW sysmask incorrect\n")));
2182             return(1);
2183         }
2184     }
2185     if(newr->psw.IA & 0x01)
2186     {
2187         DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW has ODD IA\n")));
2188         return(1);
2189     }
2190     return(0);
2191 }
2192 int     ecpsvm_dossm(REGS *regs,int b2,VADR effective_addr2)
2193 {
2194     BYTE  reqmask;
2195     BYTE *cregs;
2196     U32   creg0;
2197     REGS  npregs;
2198 
2199     SASSIST_PROLOG(SSM);
2200 
2201 
2202     /* Reject if V PSW is in problem state */
2203     if(CR6 & ECPSVM_CR6_VIRTPROB)
2204     {
2205         DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM reject : V PB State\n"));
2206         return(1);
2207     }
2208     /*
2209     if(!(micevma & MICSTSM))
2210     {
2211         DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM reject : SSM Disabled in MICEVMA; EVMA=%2.2X\n",micevma));
2212         return(1);
2213     }
2214     */
2215     /* Get CR0 - set ref bit on  fetched CR0 (already done in prolog for MICBLOK) */
2216     cregs=MADDR(micblok.MICCREG,USE_REAL_ADDR,regs,ACCTYPE_READ,0);
2217     FETCH_FW(creg0,cregs);
2218 
2219     /* Reject if V CR0 specifies SSM Suppression */
2220     if(creg0 & 0x40000000)
2221     {
2222         DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM reject : V SSM Suppr\n"));
2223         return(1);
2224     }
2225     /* Load the requested SSM Mask */
2226     /* USE Normal vfetchb here ! not only do we want tranlsation */
2227     /* but also fetch protection control, ref bit, etc.. */
2228     reqmask=ARCH_DEP(vfetchb) (effective_addr2,b2,regs);
2229 
2230     INITPSEUDOREGS(npregs);
2231     /* Load the virtual PSW AGAIN in a new structure */
2232 
2233     ARCH_DEP(load_psw) (&npregs,vpswa_p);
2234 
2235     npregs.psw.sysmask=reqmask;
2236 
2237     if(ecpsvm_check_pswtrans(regs,&micblok,micpend,&vpregs,&npregs))       /* Check PSW transition capability */
2238     {
2239         DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM Reject : New PSW too complex\n"));
2240         return(1); /* Something in the NEW PSW we can't handle.. let CP do it */
2241     }
2242 
2243     /* While we are at it, set the IA in the V PSW */
2244     SET_PSW_IA(regs);
2245     UPD_PSW_IA(&npregs, regs->psw.IA);
2246 
2247     /* Set the change bit */
2248     MADDR(vpswa,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0);
2249     /* store the new PSW */
2250     ARCH_DEP(store_psw) (&npregs,vpswa_p);
2251     DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM Complete : new SM = %2.2X\n",reqmask));
2252     DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST SSM New VIRT "));
2253     DEBUG_SASSISTX(LPSW,display_psw(&npregs));
2254     DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST SSM New REAL "));
2255     DEBUG_SASSISTX(LPSW,display_psw(regs));
2256     SASSIST_HIT(SSM);
2257     return(0);
2258 }
2259 
2260 int     ecpsvm_dosvc(REGS *regs,int svccode)
2261 {
2262     PSA_3XX *psa;
2263     REGS newr;
2264 
2265     SASSIST_PROLOG(SVC);
2266 
2267     if(svccode==76)     /* NEVER trap SVC 76 */
2268     {
2269         DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Reject : SVC 76\n"));
2270         return(1);
2271     }
2272     if(CR6 & ECPSVM_CR6_SVCINHIB)
2273     {
2274         DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Reject : SVC Assist Inhibit\n"));
2275         return(1);      /* SVC SASSIST INHIBIT ON */
2276     }
2277     /* Get what the NEW PSW should be */
2278 
2279     psa=(PSA_3XX *)MADDR((VADR)0 , USE_PRIMARY_SPACE, regs, ACCTYPE_READ, 0);
2280                                                                                          /* Use all around access key 0 */
2281                                                                                          /* Also sets reference bit     */
2282     INITPSEUDOREGS(newr);
2283     ARCH_DEP(load_psw) (&newr, (BYTE *)&psa->svcnew);   /* Ref bit set above */
2284     DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC NEW VIRT "));
2285     DEBUG_SASSISTX(SVC,display_psw(&newr));
2286     /* Get some stuff from the REAL Running PSW to put in OLD SVC PSW */
2287     SET_PSW_IA(regs);
2288     UPD_PSW_IA(&vpregs, regs->psw.IA);            /* Instruction Address */
2289     vpregs.psw.cc=regs->psw.cc;                   /* Condition Code      */
2290     vpregs.psw.pkey=regs->psw.pkey;               /* Protection Key      */
2291     vpregs.psw.progmask=regs->psw.progmask;       /* Program Mask        */
2292     vpregs.psw.intcode=svccode;                   /* SVC Interrupt code  */
2293     DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC OLD VIRT "));
2294     DEBUG_SASSISTX(SVC,display_psw(&vpregs));
2295 
2296     if(ecpsvm_check_pswtrans(regs,&micblok,micpend,&vpregs,&newr))       /* Check PSW transition capability */
2297     {
2298         DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Reject : Cannot make transition to new PSW\n"));
2299         return(1); /* Something in the NEW PSW we can't handle.. let CP do it */
2300     }
2301     /* Store the OLD SVC PSW */
2302 // ZZ    psa=(PSA_3XX *)MADDR((VADR)0, USE_PRIMARY_SPACE, regs, ACCTYPE_WRITE, 0);
2303                                                                                          /* Use all around access key 0 */
2304                                                                                          /* Also sets change bit        */
2305     /* Set intcode in PSW (for BC mode) */
2306 
2307 
2308     ARCH_DEP(store_psw) (&vpregs, (BYTE *)&psa->svcold);
2309 
2310     if(ECMODE(&vpregs.psw))
2311     {
2312         /* Also set SVC interrupt code */
2313         /* and ILC                     */
2314         STORE_FW((BYTE *)&psa->svcint,0x00020000 | svccode);
2315     }
2316     /*
2317      * Now, update some stuff in the REAL PSW
2318      */
2319     SASSIST_LPSW(newr);
2320     /*
2321      * Now store the new PSW in the area pointed by the MICBLOK
2322      */
2323     ARCH_DEP(store_psw) (&newr,vpswa_p);
2324     DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Done\n"));
2325     SASSIST_HIT(SVC);
2326     return(0);
2327 }
2328 /* LPSW Assist */
2329 int ecpsvm_dolpsw(REGS *regs,int b2,VADR e2)
2330 {
2331     BYTE * nlpsw;
2332     REGS nregs;
2333 
2334     SASSIST_PROLOG(LPSW);
2335     /* Reject if V PSW is in problem state */
2336     if(CR6 & ECPSVM_CR6_VIRTPROB)
2337     {
2338         DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW reject : V PB State\n"));
2339         return(1);
2340     }
2341     /* Reject if MICEVMA says not to do LPSW sim */
2342     if(!(micevma & MICLPSW))
2343     {
2344         DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW reject : LPSW disabled in MICEVMA\n"));
2345         return(1);
2346     }
2347     if(e2&0x03)
2348     {
2349         DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW %6.6X - Alignement error\n",e2));
2350         return(1);
2351 
2352     }
2353     nlpsw=MADDR(e2,b2,regs,ACCTYPE_READ,regs->psw.pkey);
2354     INITPSEUDOREGS(nregs);
2355     ARCH_DEP(load_psw) (&nregs,nlpsw);
2356     if(ecpsvm_check_pswtrans(regs,&micblok,micpend,&vpregs,&nregs))
2357     {
2358         DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW Rejected - Cannot make PSW transition\n"));
2359         return(1);
2360 
2361     }
2362     SASSIST_LPSW(nregs);
2363     MADDR(vpswa,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0);
2364                         /* Set ref bit in address pointed by MICBLOK */
2365     ARCH_DEP(store_psw) (&nregs,vpswa_p);
2366     DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW New VIRT "));
2367     DEBUG_SASSISTX(LPSW,display_psw(&nregs));
2368     DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW New REAL "));
2369     DEBUG_SASSISTX(LPSW,display_psw(regs));
2370     SASSIST_HIT(LPSW);
2371     return(0);
2372 }
2373 
2374 
2375 int     ecpsvm_virttmr_ext(REGS *regs)
2376 {
2377     DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Checking if we can IRPT\n"));
2378     DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Virtual"));
2379     DEBUG_SASSISTX(VTIMER,display_psw(regs));
2380     if(IS_IC_ECPSVTIMER(regs))
2381     {
2382         DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Not pending\n"));
2383         return(1);
2384     }
2385     if(!PROBSTATE(&regs->psw))
2386     {
2387         DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Not dispatching a VM\n"));
2388         return(1);
2389     }
2390     if(!(regs->psw.sysmask & PSW_EXTMASK))
2391     {
2392         DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Test int : Not enabled for EXT\n"));
2393         return(1);
2394     }
2395     if(!(regs->CR_L(6) & ECPSVM_CR6_VIRTTIMR))
2396     {
2397         DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Test int : Not enabled for VTIMER\n"));
2398         return(1);
2399     }
2400     DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Please, do\n"));
2401     return(0);
2402 }
2403 
2404 /* SIO/SIOF Assist */
2405 int ecpsvm_dosio(REGS *regs,int b2,VADR e2)
2406 {
2407     SASSIST_PROLOG(SIO);
2408     UNREFERENCED(b2);
2409     UNREFERENCED(e2);
2410     return(1);
2411 }
2412 int ecpsvm_dostnsm(REGS *regs,int b1,VADR effective_addr1,int imm2)
2413 {
2414     SASSIST_PROLOG(STNSM);
2415     UNREFERENCED(b1);
2416     UNREFERENCED(effective_addr1);
2417     UNREFERENCED(imm2);
2418     return(1);
2419 }
2420 int ecpsvm_dostosm(REGS *regs,int b1,VADR effective_addr1,int imm2)
2421 {
2422     SASSIST_PROLOG(STOSM);
2423     UNREFERENCED(b1);
2424     UNREFERENCED(effective_addr1);
2425     UNREFERENCED(imm2);
2426     return(1);
2427 }
2428 
2429 int ecpsvm_dostctl(REGS *regs,int r1,int r3,int b2,VADR effective_addr2)
2430 {
2431     SASSIST_PROLOG(STCTL);
2432 
2433     UNREFERENCED(r1);
2434     UNREFERENCED(r3);
2435     UNREFERENCED(b2);
2436     UNREFERENCED(effective_addr2);
2437     return(1);
2438 }
2439 int ecpsvm_dolctl(REGS *regs,int r1,int r3,int b2,VADR effective_addr2)
2440 {
2441     U32 crs[16];        /* New CRs */
2442     U32 rcrs[16];       /* REAL CRs */
2443     U32 ocrs[16];       /* Old CRs */
2444     BYTE *ecb_p;
2445     VADR F_ECBLOK,vmb;
2446     BYTE B_VMPSTAT;
2447 
2448     int i,j,numcrs;
2449 
2450     SASSIST_PROLOG(LCTL);
2451 
2452     if(effective_addr2 & 0x03)
2453     {
2454         DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : Not aligned\n"));
2455         return(1);
2456     }
2457 
2458     vmb=vpswa-0xA8;
2459     B_VMPSTAT=EVM_IC(vmb+VMPSTAT);
2460 
2461     if((!(B_VMPSTAT & VMV370R)) && ((r1!=r3) || (r1!=0)))
2462     {
2463         DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : BC Mode VM & LCTL != 0,0\n"));
2464         return(1);
2465     }
2466     /* Determine the range of CRs to be loaded */
2467     if(r1>r3)
2468     {
2469         numcrs=(r3+16)-r1;
2470     }
2471     else
2472     {
2473         numcrs=r3-r1;
2474     }
2475     numcrs++;
2476     for(j=r1,i=0;i<numcrs;i++,j++)
2477     {
2478         if(j>15)
2479         {
2480             j-=16;
2481         }
2482         crs[j]=ARCH_DEP(vfetch4)((effective_addr2+(i*4)) & ADDRESS_MAXWRAP(regs),b2,regs);
2483     }
2484     if(B_VMPSTAT & VMV370R)
2485     {
2486         F_ECBLOK=fetch_fw(regs->mainstor+vmb+VMECEXT);
2487     for(i=0;i<16;i++)
2488     {
2489         ecb_p=MADDR(F_ECBLOK+(i*4),USE_REAL_ADDR,regs,ACCTYPE_READ,0);
2490         ocrs[i]=fetch_fw(ecb_p);
2491     }
2492     }
2493     else
2494     {
2495         F_ECBLOK=vmb+VMECEXT;  /* Update ECBLOK ADDRESS for VCR0 Update */
2496     ecb_p=MADDR(F_ECBLOK,USE_REAL_ADDR,regs,ACCTYPE_READ,0);
2497         /* Load OLD CR0 From VMBLOK */
2498     ocrs[0]=fetch_fw(ecb_p);
2499     }
2500     for(i=0;i<16;i++)
2501     {
2502         rcrs[i]=regs->CR_L(i);
2503     }
2504     /* Source safely loaded into "crs" array */
2505     /* Load the CRS - exit from loop if it's not possible */
2506     DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL %d,%d : Modifying %d cregs\n",r1,r3,numcrs));
2507     for(j=r1,i=0;i<numcrs;i++,j++)
2508     {
2509         if(j>15)
2510         {
2511             j-=16;
2512         }
2513         switch(j)
2514         {
2515             case 0:     /* CR0 Case */
2516                 /* Check 1st 2 bytes of CR0 - No change allowed */
2517                 if((ocrs[0] & 0xffff0000) != (crs[0] & 0xffff0000))
2518                 {
2519                     DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR0 High changed\n"));
2520                     return 1;
2521                 }
2522                 /* Not allowed if : NEW mask is being enabled AND MICPEND AND PSW has EXT enabled */
2523                 if(vpregs.psw.sysmask & 0x01)
2524                 {
2525                     if(micpend & 0x80)
2526                     {
2527                         if((~(ocrs[0] & 0xffff)) & (crs[0] & 0xffff))
2528                         {
2529                             DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR0 EXTSM Enables new EXTS\n"));
2530                             return 1;
2531                         }
2532                     }
2533                 }
2534                 ocrs[0]=crs[0];
2535                 break;
2536             case 1:
2537                 if(ocrs[1] != crs[1])
2538                 {
2539                     DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR1 Updates shadow table\n"));
2540                     return 1;
2541                 }
2542                 break;
2543             case 2:
2544                 /* Not allowed if : NEW Channel mask is turned on AND micpend AND PSW Extended I/O Mask is on */
2545                 if(vpregs.psw.sysmask & 0x02)
2546                 {
2547                     if((~ocrs[2]) & crs[2])
2548                     {
2549                         if(micpend & 0x80)
2550                         {
2551                             DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR2 IOCSM Enables I/O Ints\n"));
2552                             return(1);
2553                         }
2554                     }
2555                 }
2556                 ocrs[2]=crs[2];
2557                 break;
2558             case 3:     /* DAS Control regs (not used under VM/370) */
2559             case 4:
2560             case 5:
2561             case 7:
2562 /*  2017-01-12
2563     LCTL assist should not update real CR3-CR7 with values from a virtual machine execution of LCTL.
2564     CR3-CR7 are for the DAS feature.  If any of these four control registers are specified then
2565     the assist should kick it back to CP and let CP handle it, because different versions of VM do
2566     different things with these CRs depending on whether DAS is available or not.                    */
2567 
2568 // original code:
2569 //                ocrs[j]=crs[j];
2570 //                rcrs[j]=crs[j]
2571 //                break;
2572 
2573 // replacement code:
2574                 DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : DAS CR%d Update\n",j));
2575                 return(1);
2576 /* end of 2017-01-12 */
2577             case 6: /* VCR6 Ignored on real machine */
2578                 ocrs[j]=crs[j];
2579                 break;
2580             case 8: /* Monitor Calls */
2581                 DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : MC CR8 Update\n"));
2582                 return(1);
2583             case 9: /* PER Control Regs */
2584             case 10:
2585             case 11:
2586                 DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : PER CR%d Update\n",j));
2587                 return(1);
2588             case 12:
2589             case 13: /* 12-13 : Unused */
2590                 ocrs[j]=crs[j];
2591                 rcrs[j]=crs[j];
2592                 break;
2593             case 14:
2594             case 15: /* 14-15 Machine Check & I/O Logout control (plus DAS) */
2595                 ocrs[j]=crs[j];
2596                 break;
2597             default:
2598                 break;
2599         }
2600     }
2601     /* Update REAL Control regs */
2602     for(i=0;i<16;i++)
2603     {
2604         regs->CR_L(i)=rcrs[i];
2605     }
2606     /* Update ECBLOK/VMBLOK Control regs */
2607     /* Note : if F_ECBLOK addresses VMVCR0 in the VMBLOCK */
2608     /*        check has already been done to make sure    */
2609     /*        r1=0 and numcrs=1                           */
2610     for(j=r1,i=0;i<numcrs;i++,j++)
2611     {
2612         if(j>15)
2613         {
2614             j-=16;
2615         }
2616     ecb_p=MADDR(F_ECBLOK+(j*4),USE_REAL_ADDR,regs,ACCTYPE_WRITE,0);
2617     store_fw(ecb_p,ocrs[j]);
2618     }
2619     DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL %d,%d Done\n",r1,r3));
2620     SASSIST_HIT(LCTL);
2621     return 0;
2622 }
2623 int ecpsvm_doiucv(REGS *regs,int b2,VADR effective_addr2)
2624 {
2625     SASSIST_PROLOG(IUCV);
2626 
2627     UNREFERENCED(b2);
2628     UNREFERENCED(effective_addr2);
2629     return(1);
2630 }
2631 int ecpsvm_dodiag(REGS *regs,int r1,int r3,int b2,VADR effective_addr2)
2632 {
2633     SASSIST_PROLOG(DIAG);
2634     UNREFERENCED(r1);
2635     UNREFERENCED(r3);
2636     UNREFERENCED(b2);
2637     UNREFERENCED(effective_addr2);
2638     return(1);
2639 }
2640 static char *ecpsvm_stat_sep="HHCEV003I +-----------+----------+----------+-------+\n";
2641 
2642 static int ecpsvm_sortstats(const void *a,const void *b)
2643 {
2644     ECPSVM_STAT *ea,*eb;
2645     ea=(ECPSVM_STAT *)a;
2646     eb=(ECPSVM_STAT *)b;
2647     return(eb->call-ea->call);
2648 }
2649 
2650 static void ecpsvm_showstats2(ECPSVM_STAT *ar,size_t count)
2651 {
2652     char *sep=ecpsvm_stat_sep;
2653     char nname[32];
2654     int  havedisp=0;
2655     int  notshown=0;
2656     size_t unsupcc=0;
2657     int haveunsup=0;
2658     int callt=0;
2659     int hitt=0;
2660     size_t i;
2661     for(i=0;i<count;i++)
2662     {
2663         if(ar[i].call)
2664         {
2665             callt+=ar[i].call;
2666             hitt+=ar[i].hit;
2667             if(!ar[i].support)
2668             {
2669                 unsupcc+=ar[i].call;
2670                 haveunsup++;
2671             }
2672             havedisp=1;
2673             snprintf(nname,32,"%s%s",ar[i].name,ar[i].support ? "" : "*");
2674             if(!ar[i].enabled)
2675             {
2676                 strcat(nname,"-");
2677             }
2678             if(ar[i].debug)
2679             {
2680                 strcat(nname,"%");
2681             }
2682             if(ar[i].total)
2683             {
2684                 strcat(nname,"+");
2685             }
2686             logmsg(_("HHCEV001I | %-9s | %8d | %8d |  %3d%% |\n"),
2687                     nname,
2688                     ar[i].call,
2689                     ar[i].hit,
2690                     ar[i].call ?
2691                             (ar[i].hit*100)/ar[i].call :
2692                             100);
2693         }
2694         else
2695         {
2696             notshown++;
2697         }
2698     }
2699     if(havedisp)
2700     {
2701         logmsg(sep);
2702     }
2703     logmsg(_("HHCEV001I | %-9s | %8d | %8d |  %3d%% |\n"),
2704             "Total",
2705             callt,
2706             hitt,
2707             callt ?
2708                     (hitt*100)/callt :
2709                     100);
2710     logmsg(sep);
2711     if(haveunsup)
2712     {
2713         logmsg(_("HHCEV004I * : Unsupported, - : Disabled, %% - Debug\n"));
2714     }
2715     if(notshown)
2716     {
2717         logmsg(_("HHCEV005I %d Entr%s not shown (never invoked)\n"),notshown,notshown==1?"y":"ies");
2718     }
2719     if(unsupcc)
2720     {
2721         if(unsupcc==1)
2722         {
2723                 logmsg(_("HHCEV006I 1 call was made to an unsupported function\n"));
2724         }
2725         else
2726         {
2727             logmsg(_("HHCEV006I %d calls where made to unsupported functions\n"),unsupcc);
2728         }
2729     }
2730     return;
2731 }
2732 /* SHOW STATS */
2733 void ecpsvm_showstats(int ac,char **av)
2734 {
2735     size_t      asize;
2736     ECPSVM_STAT *ar;
2737     char *sep=ecpsvm_stat_sep;
2738 
2739     UNREFERENCED(ac);
2740     UNREFERENCED(av);
2741     logmsg(sep);
2742     logmsg(_("HHCEV002I | %-9s | %-8s | %-8s | %-5s |\n"),"VM ASSIST","Calls","Hits","Ratio");
2743     logmsg(sep);
2744     ar=malloc(sizeof(ecpsvm_sastats));
2745     memcpy(ar,&ecpsvm_sastats,sizeof(ecpsvm_sastats));
2746     asize=sizeof(ecpsvm_sastats)/sizeof(ECPSVM_STAT);
2747     qsort(ar,asize,sizeof(ECPSVM_STAT),ecpsvm_sortstats);
2748     ecpsvm_showstats2(ar,asize);
2749     free(ar);
2750     logmsg(sep);
2751     logmsg(_("HHCEV002I | %-9s | %-8s | %-8s | %-5s |\n"),"CP ASSIST","Calls","Hits","Ratio");
2752     logmsg(sep);
2753     ar=malloc(sizeof(ecpsvm_cpstats));
2754     memcpy(ar,&ecpsvm_cpstats,sizeof(ecpsvm_cpstats));
2755     asize=sizeof(ecpsvm_cpstats)/sizeof(ECPSVM_STAT);
2756     qsort(ar,asize,sizeof(ECPSVM_STAT),ecpsvm_sortstats);
2757     ecpsvm_showstats2(ar,asize);
2758     free(ar);
2759 }
2760 
2761 
2762 ECPSVM_STAT *ecpsvm_findstat(char *feature,char **fclass)
2763 {
2764     ECPSVM_STAT *es;
2765     ECPSVM_STAT *esl;
2766     int i;
2767     int fcount;
2768     fcount=sizeof(ecpsvm_sastats)/sizeof(ECPSVM_STAT);
2769     esl=(ECPSVM_STAT *)&ecpsvm_sastats;
2770     for(i=0;i<fcount;i++)
2771     {
2772         es=&esl[i];
2773         if(strcasecmp(feature,es->name)==0)
2774         {
2775             *fclass="VM ASSIST";
2776             return(es);
2777         }
2778     }
2779     esl=(ECPSVM_STAT *)&ecpsvm_cpstats;
2780     fcount=sizeof(ecpsvm_cpstats)/sizeof(ECPSVM_STAT);
2781     for(i=0;i<fcount;i++)
2782     {
2783         es=&esl[i];
2784         if(strcasecmp(feature,es->name)==0)
2785         {
2786             *fclass="CP ASSIST";
2787             return(es);
2788         }
2789     }
2790     return(NULL);
2791 }
2792 
2793 void ecpsvm_enadisaall(char *fclass,ECPSVM_STAT *tbl,size_t count,int onoff,int debug)
2794 {
2795     ECPSVM_STAT *es;
2796     size_t i;
2797     char *enadisa,*debugonoff;
2798     enadisa=onoff?"Enabled":"Disabled";
2799     debugonoff=debug?"On":"Off";
2800     for(i=0;i<count;i++)
2801     {
2802         es=&tbl[i];
2803         if(onoff>=0)
2804         {
2805             es->enabled=onoff;
2806             logmsg(_("HHCEV015I ECPS:VM %s feature %s %s\n"),fclass,es->name,enadisa);
2807         }
2808         if(debug>=0)
2809         {
2810             es->debug=debug;
2811             logmsg(_("HHCEV015I ECPS:VM %s feature %s Debug %s\n"),fclass,es->name,debugonoff);
2812         }
2813     }
2814     if(onoff>=0)
2815     {
2816         logmsg(_("HHCEV016I All ECPS:VM %s features %s\n"),fclass,enadisa);
2817     }
2818     if(debug>=0)
2819     {
2820         logmsg(_("HHCEV016I All ECPS:VM %s features Debug %s\n"),fclass,debugonoff);
2821     }
2822 }
2823 
2824 void ecpsvm_enable_disable(int ac,char **av,int onoff,int debug)
2825 {
2826     char        *fclass;
2827     char        *enadisa,*debugonoff;
2828     int i;
2829 
2830     size_t      sacount,cpcount;
2831     ECPSVM_STAT *es;
2832     ECPSVM_STAT *sal,*cpl;
2833 
2834     sal=(ECPSVM_STAT *)&ecpsvm_sastats;
2835     cpl=(ECPSVM_STAT *)&ecpsvm_cpstats;
2836     sacount=sizeof(ecpsvm_sastats)/sizeof(ECPSVM_STAT);
2837     cpcount=sizeof(ecpsvm_cpstats)/sizeof(ECPSVM_STAT);
2838 
2839     enadisa=onoff?"Enabled":"Disabled";
2840     debugonoff=debug?"On":"Off";
2841     if(ac==1)
2842     {
2843         ecpsvm_enadisaall("VM ASSIST",sal,sacount,onoff,debug);
2844         ecpsvm_enadisaall("CP ASSIST",cpl,cpcount,onoff,debug);
2845         if(debug>=0)
2846         {
2847             sysblk.ecpsvm.debug=debug;
2848             logmsg(_("HHCEV013I ECPS:VM Global Debug %s\n"),debugonoff);
2849         }
2850         return;
2851     }
2852     for(i=1;i<ac;i++)
2853     {
2854         if(strcasecmp(av[i],"ALL")==0)
2855         {
2856             ecpsvm_enadisaall("VM ASSIST",sal,sacount,onoff,debug);
2857             ecpsvm_enadisaall("CP ASSIST",cpl,cpcount,onoff,debug);
2858             return;
2859         }
2860         if(strcasecmp(av[i],"VMA")==0)
2861         {
2862             ecpsvm_enadisaall("VM ASSIST",sal,sacount,onoff,debug);
2863             return;
2864         }
2865         if(strcasecmp(av[i],"CPA")==0)
2866         {
2867             ecpsvm_enadisaall("CP ASSIST",cpl,cpcount,onoff,debug);
2868             return;
2869         }
2870         es=ecpsvm_findstat(av[i],&fclass);
2871         if(es!=NULL)
2872         {
2873             if(onoff>=0)
2874             {
2875                 es->enabled=onoff;
2876                 logmsg(_("HHCEV014I ECPS:VM %s feature %s %s\n"),fclass,es->name,enadisa);
2877             }
2878             if(debug>=0)
2879             {
2880                 es->debug=onoff;
2881                 logmsg(_("HHCEV014I ECPS:VM %s feature %s Debug %s\n"),fclass,es->name,debugonoff);
2882             }
2883         }
2884         else
2885         {
2886             logmsg(_("HHCEV014I Unknown ECPS:VM feature %s; Ignored\n"),av[i]);
2887         }
2888     }
2889 }
2890 
2891 void ecpsvm_disable(int ac,char **av)
2892 {
2893     ecpsvm_enable_disable(ac,av,0,-1);
2894 }
2895 void ecpsvm_enable(int ac,char **av)
2896 {
2897     ecpsvm_enable_disable(ac,av,1,-1);
2898 }
2899 void ecpsvm_debug(int ac,char **av)
2900 {
2901     ecpsvm_enable_disable(ac,av,-1,1);
2902 }
2903 void ecpsvm_nodebug(int ac,char **av)
2904 {
2905     ecpsvm_enable_disable(ac,av,-1,0);
2906 }
2907 
2908 void ecpsvm_level(int ac,char **av)
2909 {
2910     int lvl;
2911     if(sysblk.ecpsvm.available)
2912     {
2913         logmsg(_("HHCEV016I Current reported ECPS:VM Level is %d\n"),sysblk.ecpsvm.level);
2914     }
2915     else
2916     {
2917         logmsg(_("HHCEV016I Current reported ECPS:VM Level is %d\n"),sysblk.ecpsvm.level);
2918         logmsg(_("HHCEV017I But ECPS:VM is currently disabled\n"));
2919     }
2920     if(ac>1)
2921     {
2922         lvl=atoi(av[1]);
2923         logmsg(_("HHCEV016I Level reported to guest program is now %d\n"),lvl);
2924         sysblk.ecpsvm.level=lvl;
2925     }
2926     if(sysblk.ecpsvm.level!=20)
2927     {
2928           logmsg(_("HHCEV017W WARNING ! current level (%d) is not supported\n"),sysblk.ecpsvm.level);
2929           logmsg(_("HHCEV018W WARNING ! Unpredictable results may occur\n"));
2930           logmsg(_("HHCEV019I The microcode support level is 20\n"));
2931     }
2932 }
2933 
2934 static  void ecpsvm_helpcmd(int,char **);
2935 
2936 static ECPSVM_CMDENT ecpsvm_cmdtab[]={
2937     {"Help",1,ecpsvm_helpcmd,"Show help","format : \"evm help [cmd]\" Shows help on the specified\n"
2938                                                         "        ECPSVM subcommand\n"},
2939     {"STats",2,ecpsvm_showstats,"Show statistical counters","format : evm stats : Shows various ECPS:VM Counters\n"},
2940     {"DIsable",2,ecpsvm_disable,"Disable ECPS:VM Features","format : evm disable [ALL|feat1[ feat2|...]\n"},
2941     {"ENable",2,ecpsvm_enable,"Enable ECPS:VM Features","format : evm enable [ALL|feat1[ feat2|...]\n"},
2942 #if defined(DEBUG_SASSIST) || defined(DEBUG_CPASSIST)
2943     {"DEBUG",5,ecpsvm_debug,"Debug ECPS:VM Features","format : evm debug [ALL|feat1[ feat2|...]\n"},
2944     {"NODebug",3,ecpsvm_nodebug,"Turn Debug off for ECPS:VM Features","format : evm NODebug [ALL|feat1[ feat2|...]\n"},
2945 #endif
2946     {"Level",1,ecpsvm_level,"Set/Show ECPS:VM level","format : evm Level [nn]\n"},
2947     {NULL,0,NULL,NULL,NULL}};
2948 
2949 static void ecpsvm_helpcmdlist(void)
2950 {
2951     int i;
2952     ECPSVM_CMDENT *ce;
2953 
2954     for(i=0;ecpsvm_cmdtab[i].name;i++)
2955     {
2956         ce=&ecpsvm_cmdtab[i];
2957         logmsg(_("HHCEV010I : %s : %s\n"),ce->name,ce->expl);
2958     }
2959     return;
2960 }
2961 
2962 void ecpsvm_helpcmd(int ac,char **av)
2963 {
2964     ECPSVM_CMDENT *ce;
2965     if(ac==1)
2966     {
2967         ecpsvm_helpcmdlist();
2968         return;
2969     }
2970     ce=ecpsvm_getcmdent(av[1]);
2971     if(ce==NULL)
2972     {
2973         logmsg(_("HHCEV011E Unknown subcommand %s - valid subcommands are :\n"),av[1]);
2974         ecpsvm_helpcmdlist();
2975         return;
2976     }
2977     logmsg(_("HHCEV012I : %s : %s"),ce->name,ce->help);
2978     return;
2979 }
2980 
2981 ECPSVM_CMDENT *ecpsvm_getcmdent(char *cmd)
2982 {
2983     ECPSVM_CMDENT *ce;
2984     int i;
2985     int clen;
2986     for(i=0;ecpsvm_cmdtab[i].name;i++)
2987     {
2988         ce=&ecpsvm_cmdtab[i];
2989         if(strlen(cmd)<=strlen(ce->name) && strlen(cmd)>=(size_t)ce->abbrev)
2990         {
2991             clen=strlen(cmd);
2992             if(strncasecmp(cmd,ce->name,clen)==0)
2993             {
2994                 return(ce);
2995             }
2996         }
2997     }
2998     return(NULL);
2999 }
3000 void ecpsvm_command(int ac,char **av)
3001 {
3002     ECPSVM_CMDENT *ce;
3003     logmsg(_("HHCEV011I ECPS:VM Command processor invoked\n"));
3004     if(ac==1)
3005     {
3006         logmsg(_("HHCEV008E NO EVM subcommand. Type \"evm help\" for a list of valid subcommands\n"));
3007         return;
3008     }
3009     ce=ecpsvm_getcmdent(av[1]);
3010     if(ce==NULL)
3011     {
3012         logmsg(_("HHCEV008E Unknown EVM subcommand %s\n"),av[1]);
3013         return;
3014     }
3015     ce->fun(ac-1,av+1);
3016     logmsg(_("HHCEV011I ECPS:VM Command processor complete\n"));
3017 }
3018 
3019 #endif /* ifdef FEATURE_ECPSVM */
3020 
3021 /* Note : The following forces inclusion for S/390 & z/ARCH */
3022 /*        This is necessary just in order to properly define */
3023 /*        S/390 auxialiary routines invoked by S/370 routines */
3024 /*        because of SIE                                     */
3025 
3026 #if !defined(_GEN_ARCH)
3027 
3028 #if defined(_ARCHMODE2)
3029  #define  _GEN_ARCH _ARCHMODE2
3030  #include "ecpsvm.c"
3031 #endif
3032 
3033 #if defined(_ARCHMODE3)
3034  #undef   _GEN_ARCH
3035  #define  _GEN_ARCH _ARCHMODE3
3036  #include "ecpsvm.c"
3037 #endif
3038 
3039 #endif /*!defined(_GEN_ARCH)*/
3040