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(®s->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(®s->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