1 /* EXTERNAL.C (c) Copyright Roger Bowler, 1999-2009 */
2 /* ESA/390 External Interrupt and Timer */
3
4 /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */
5 /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */
6
7 /*-------------------------------------------------------------------*/
8 /* This module implements external interrupt, timer, and signalling */
9 /* functions for the Hercules ESA/390 emulator. */
10 /*-------------------------------------------------------------------*/
11
12 /*-------------------------------------------------------------------*/
13 /* Additional credits: */
14 /* TOD clock offset contributed by Jay Maynard */
15 /* Correction to timer interrupt by Valery Pogonchenko */
16 /* TOD clock drag factor contributed by Jan Jaeger */
17 /* CPU timer and clock comparator interrupt improvements by */
18 /* Jan Jaeger, after a suggestion by Willem Koynenberg */
19 /* Prevent TOD clock and CPU timer from going back - Jan Jaeger */
20 /* Use longjmp on all interrupt types - Jan Jaeger */
21 /* Fix todclock - Jay Maynard */
22 /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */
23 /*-------------------------------------------------------------------*/
24
25 #include "hstdinc.h"
26
27 #if !defined(_HENGINE_DLL_)
28 #define _HENGINE_DLL_
29 #endif
30
31 #if !defined(_EXTERNAL_C_)
32 #define _EXTERNAL_C_
33 #endif
34
35 #include "hercules.h"
36 #include "opcode.h"
37 #include "inline.h"
38
39 /*-------------------------------------------------------------------*/
40 /* Load external interrupt new PSW */
41 /*-------------------------------------------------------------------*/
ARCH_DEP(external_interrupt)42 static void ARCH_DEP(external_interrupt) (int code, REGS *regs)
43 {
44 RADR pfx;
45 PSA *psa;
46 int rc;
47
48 PTT(PTT_CL_SIG,"*EXTINT",code,regs->cpuad,regs->psw.IA_L);
49
50 #if defined(_FEATURE_SIE)
51 /* Set the main storage reference and change bits */
52 if(SIE_MODE(regs)
53 #if defined(_FEATURE_EXPEDITED_SIE_SUBSET)
54 && !SIE_FEATB(regs, S, EXP_TIMER)
55 #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/
56 #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST)
57 && !SIE_FEATB(regs, EC0, EXTA)
58 #endif
59 )
60 {
61 /* Point to SIE copy of PSA in state descriptor */
62 psa = (void*)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_IP_PSA_OFFSET);
63 STORAGE_KEY(SIE_STATE(regs), regs->hostregs) |= (STORKEY_REF | STORKEY_CHANGE);
64 }
65 else
66 #endif /*defined(_FEATURE_SIE)*/
67 {
68 /* Point to PSA in main storage */
69 pfx = regs->PX;
70 #if defined(_FEATURE_EXPEDITED_SIE_SUBSET)
71 SIE_TRANSLATE(&pfx, ACCTYPE_SIE, regs);
72 #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/
73 psa = (void*)(regs->mainstor + pfx);
74 STORAGE_KEY(pfx, regs) |= (STORKEY_REF | STORKEY_CHANGE);
75 }
76
77 /* Store the interrupt code in the PSW */
78 regs->psw.intcode = code;
79
80
81 /* Zero extcpuad field unless extcall or ems signal or blockio */
82 if(code != EXT_EXTERNAL_CALL_INTERRUPT
83 #if defined(FEATURE_VM_BLOCKIO)
84 && code != EXT_BLOCKIO_INTERRUPT
85 #endif /* defined(FEATURE_VM_BLOCKIO) */
86 && code != EXT_EMERGENCY_SIGNAL_INTERRUPT)
87 STORE_HW(psa->extcpad,0);
88
89 #if defined(FEATURE_BCMODE)
90 /* For ECMODE, store external interrupt code at PSA+X'86' */
91 if ( ECMODE(®s->psw) )
92 #endif /*defined(FEATURE_BCMODE)*/
93 STORE_HW(psa->extint,code);
94
95 if ( !SIE_MODE(regs)
96 #if defined(_FEATURE_EXPEDITED_SIE_SUBSET)
97 || SIE_FEATB(regs, S, EXP_TIMER)
98 #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/
99 #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST)
100 || SIE_FEATB(regs, EC0, EXTA)
101 #endif
102 )
103 {
104 /* Store current PSW at PSA+X'18' */
105 ARCH_DEP(store_psw) (regs, psa->extold);
106
107 /* Load new PSW from PSA+X'58' */
108 rc = ARCH_DEP(load_psw) (regs, psa->extnew);
109
110 if ( rc )
111 {
112 RELEASE_INTLOCK(regs);
113 ARCH_DEP(program_interrupt)(regs, rc);
114 }
115 }
116
117 #if defined(FEATURE_INTERVAL_TIMER)
118 /* Ensure the interval timer is uptodate */
119 ARCH_DEP(store_int_timer_nolock) (regs);
120 #endif
121 RELEASE_INTLOCK(regs);
122
123
124 if ( SIE_MODE(regs)
125 #if defined(_FEATURE_EXPEDITED_SIE_SUBSET)
126 && !SIE_FEATB(regs, S, EXP_TIMER)
127 #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/
128 #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST)
129 && !SIE_FEATB(regs, EC0, EXTA)
130 #endif
131 )
132 longjmp (regs->progjmp, SIE_INTERCEPT_EXT);
133 else
134 longjmp (regs->progjmp, SIE_NO_INTERCEPT);
135
136 } /* end function external_interrupt */
137
138 /*-------------------------------------------------------------------*/
139 /* Perform external interrupt if pending */
140 /* */
141 /* This function is called by the CPU to check whether any */
142 /* external interrupt conditions are pending, and to perform */
143 /* an external interrupt if so. If multiple external interrupts */
144 /* are pending, then only the highest priority interrupt is taken, */
145 /* and any other interrupts remain pending. Remaining interrupts */
146 /* will be processed one-by-one during subsequent calls. */
147 /* */
148 /* Important notes: */
149 /* (i) This function must NOT be called if the CPU is disabled */
150 /* for external interrupts (PSW bit 7 is zero). */
151 /* (ii) The caller MUST hold the interrupt lock (sysblk.intlock) */
152 /* to ensure correct serialization of interrupt pending bits. */
153 /*-------------------------------------------------------------------*/
ARCH_DEP(perform_external_interrupt)154 void ARCH_DEP(perform_external_interrupt) (REGS *regs)
155 {
156 PSA *psa; /* -> Prefixed storage area */
157 U16 cpuad; /* Originating CPU address */
158 #if defined(FEATURE_VM_BLOCKIO)
159 #if defined(FEATURE_ESAME)
160 RADR servpadr; /* Address of 64-bit block I/O interrupt */
161 #endif
162 U16 servcode; /* Service Signal or Block I/O Interrupt code */
163 #endif /* defined(FEATURE_VM_BLOCKIO) */
164
165 /* External interrupt if console interrupt key was depressed */
166 if ( OPEN_IC_INTKEY(regs) && !SIE_MODE(regs) )
167 {
168 logmsg (_("HHCCP023I External interrupt: Interrupt key\n"));
169
170 /* Reset interrupt key pending */
171 OFF_IC_INTKEY;
172
173 /* Generate interrupt key interrupt */
174 ARCH_DEP(external_interrupt) (EXT_INTERRUPT_KEY_INTERRUPT, regs);
175 }
176
177 /* External interrupt if malfunction alert is pending */
178 if (OPEN_IC_MALFALT(regs))
179 {
180 /* Find first CPU which generated a malfunction alert */
181 for (cpuad = 0; regs->malfcpu[cpuad] == 0; cpuad++)
182 {
183 if (cpuad >= MAX_CPU)
184 {
185 OFF_IC_MALFALT(regs);
186 return;
187 }
188 } /* end for(cpuad) */
189
190 // /*debug*/ logmsg (_("External interrupt: Malfuction Alert from CPU %d\n"),
191 // /*debug*/ cpuad);
192
193 /* Reset the indicator for the CPU which was found */
194 regs->malfcpu[cpuad] = 0;
195
196 /* Store originating CPU address at PSA+X'84' */
197 psa = (void*)(regs->mainstor + regs->PX);
198 STORE_HW(psa->extcpad,cpuad);
199
200 /* Reset emergency signal pending flag if there are
201 no other CPUs which generated emergency signal */
202 OFF_IC_MALFALT(regs);
203 while (++cpuad < MAX_CPU)
204 {
205 if (regs->malfcpu[cpuad])
206 {
207 ON_IC_MALFALT(regs);
208 break;
209 }
210 } /* end while */
211
212 /* Generate emergency signal interrupt */
213 ARCH_DEP(external_interrupt) (EXT_MALFUNCTION_ALERT_INTERRUPT, regs);
214 }
215
216
217 /* External interrupt if emergency signal is pending */
218 if (OPEN_IC_EMERSIG(regs))
219 {
220 /* Find first CPU which generated an emergency signal */
221 for (cpuad = 0; regs->emercpu[cpuad] == 0; cpuad++)
222 {
223 if (cpuad >= MAX_CPU)
224 {
225 OFF_IC_EMERSIG(regs);
226 return;
227 }
228 } /* end for(cpuad) */
229
230 // /*debug*/ logmsg (_("External interrupt: Emergency Signal from CPU %d\n"),
231 // /*debug*/ cpuad);
232
233 /* Reset the indicator for the CPU which was found */
234 regs->emercpu[cpuad] = 0;
235
236 /* Store originating CPU address at PSA+X'84' */
237 psa = (void*)(regs->mainstor + regs->PX);
238 STORE_HW(psa->extcpad,cpuad);
239
240 /* Reset emergency signal pending flag if there are
241 no other CPUs which generated emergency signal */
242 OFF_IC_EMERSIG(regs);
243 while (++cpuad < MAX_CPU)
244 {
245 if (regs->emercpu[cpuad])
246 {
247 ON_IC_EMERSIG(regs);
248 break;
249 }
250 } /* end while */
251
252 /* Generate emergency signal interrupt */
253 ARCH_DEP(external_interrupt) (EXT_EMERGENCY_SIGNAL_INTERRUPT, regs);
254 }
255
256 /* External interrupt if external call is pending */
257 if (OPEN_IC_EXTCALL(regs))
258 {
259 // /*debug*/logmsg (_("External interrupt: External Call from CPU %d\n"),
260 // /*debug*/ regs->extccpu);
261
262 /* Reset external call pending */
263 OFF_IC_EXTCALL(regs);
264
265 /* Store originating CPU address at PSA+X'84' */
266 psa = (void*)(regs->mainstor + regs->PX);
267 STORE_HW(psa->extcpad,regs->extccpu);
268
269 /* Generate external call interrupt */
270 ARCH_DEP(external_interrupt) (EXT_EXTERNAL_CALL_INTERRUPT, regs);
271 }
272
273 /* External interrupt if TOD clock exceeds clock comparator */
274 if ( tod_clock(regs) > regs->clkc
275 && OPEN_IC_CLKC(regs) )
276 {
277 if (CPU_STEPPING_OR_TRACING_ALL)
278 {
279 logmsg (_("HHCCP024I External interrupt: Clock comparator\n"));
280 }
281 ARCH_DEP(external_interrupt) (EXT_CLOCK_COMPARATOR_INTERRUPT, regs);
282 }
283
284 /* External interrupt if CPU timer is negative */
285 if ( CPU_TIMER(regs) < 0
286 && OPEN_IC_PTIMER(regs) )
287 {
288 if (CPU_STEPPING_OR_TRACING_ALL)
289 {
290 logmsg (_("HHCCP025I External interrupt: CPU timer=%16.16" I64_FMT "X\n"),
291 (long long)CPU_TIMER(regs) << 8);
292 }
293 ARCH_DEP(external_interrupt) (EXT_CPU_TIMER_INTERRUPT, regs);
294 }
295
296 /* External interrupt if interval timer interrupt is pending */
297 #if defined(FEATURE_INTERVAL_TIMER)
298 if (OPEN_IC_ITIMER(regs)
299 #if defined(_FEATURE_SIE)
300 && !(SIE_STATB(regs, M, ITMOF))
301 #endif /*defined(_FEATURE_SIE)*/
302 )
303 {
304 if (CPU_STEPPING_OR_TRACING_ALL)
305 {
306 logmsg (_("HHCCP026I External interrupt: Interval timer\n"));
307 }
308 OFF_IC_ITIMER(regs);
309 ARCH_DEP(external_interrupt) (EXT_INTERVAL_TIMER_INTERRUPT, regs);
310 }
311
312 #if defined(FEATURE_ECPSVM)
313 if ( OPEN_IC_ECPSVTIMER(regs) )
314 {
315 OFF_IC_ECPSVTIMER(regs);
316 ARCH_DEP(external_interrupt) (EXT_VINTERVAL_TIMER_INTERRUPT,regs);
317 }
318 #endif /*FEATURE_ECPSVM*/
319 #endif /*FEATURE_INTERVAL_TIMER*/
320
321 /* External interrupt if service signal is pending */
322 if ( OPEN_IC_SERVSIG(regs) && !SIE_MODE(regs) )
323 {
324
325 #if defined(FEATURE_VM_BLOCKIO)
326
327 /* Note: Both Block I/O and Service Signal are enabled by the */
328 /* the same CR0 bit. Hence they are handled in the same code */
329 switch(sysblk.servcode)
330 {
331 case EXT_BLOCKIO_INTERRUPT: /* VM Block I/O Interrupt */
332
333 if (sysblk.biodev->ccwtrace)
334 {
335 logmsg (_("%4.4X:HHCCP031I Processing Block I/O interrupt: "
336 "code=%4.4X parm=%16.16X status=%2.2X subcode=%2.2X\n"),
337 sysblk.biodev->devnum,
338 sysblk.servcode,
339 sysblk.bioparm,
340 sysblk.biostat,
341 sysblk.biosubcd
342 );
343 }
344
345 servcode = EXT_BLOCKIO_INTERRUPT;
346
347 #if defined(FEATURE_ESAME)
348 /* Real address used to store the 64-bit interrupt parameter */
349 #define VM_BLOCKIO_INT_PARM 0x11B8
350 if (sysblk.biosubcd == 0x07)
351 {
352 /* 8-byte interrupt parm */
353
354 if (CPU_STEPPING_OR_TRACING_ALL)
355 {
356 logmsg (_("HHCCP028I External interrupt: Block I/O %16.16X\n"),
357 sysblk.bioparm);
358 }
359
360 /* Set the main storage reference and change bits */
361 /* for 64-bit interruption parameter. */
362 /* Note: This is handled for the first 4K page in */
363 /* ARCH_DEP(external_interrupt), but not for the */
364 /* the second 4K page used for the 64-bit interrupt */
365 /* parameter. */
366
367 /* Point to 2nd page of PSA in main storage */
368 servpadr=APPLY_PREFIXING(VM_BLOCKIO_INT_PARM,regs->PX);
369
370 STORAGE_KEY(servpadr, regs)
371 |= (STORKEY_REF | STORKEY_CHANGE);
372
373 #if 0
374 /* Store the 64-bit interrupt parameter */
375 logmsg (_("Saving 64-bit Block I/O interrupt parm at "
376 "%16.16X: %16.16X\n"),
377 servpadr,
378 sysblk.bioparm
379 );
380 #endif
381
382 STORE_DW(regs->mainstor + servpadr,sysblk.bioparm);
383 psa = (void*)(regs->mainstor + regs->PX);
384 }
385 else
386 {
387 #endif /* defined(FEATURE_ESAME) */
388
389 /* 4-byte interrupt parm */
390
391 if (CPU_STEPPING_OR_TRACING_ALL)
392 {
393 logmsg (_("HHCCP028I External interrupt: Block I/O %8.8X\n"),
394 (U32)sysblk.bioparm);
395 }
396
397 /* Store Block I/O parameter at PSA+X'80' */
398 psa = (void*)(regs->mainstor + regs->PX);
399 STORE_FW(psa->extparm,(U32)sysblk.bioparm);
400
401 #if defined(FEATURE_ESAME)
402 }
403 #endif
404
405 /* Store sub-interruption code and status at PSA+X'84' */
406 STORE_HW(psa->extcpad,(sysblk.biosubcd<<8)|sysblk.biostat);
407
408 /* Reset interruption data */
409 sysblk.bioparm = 0;
410 sysblk.biosubcd = 0;
411 sysblk.biostat = 0;
412
413 break;
414
415 case EXT_SERVICE_SIGNAL_INTERRUPT: /* Service Signal */
416 default:
417 servcode = EXT_SERVICE_SIGNAL_INTERRUPT;
418
419 /* Apply prefixing if the parameter is a storage address */
420 if ( (sysblk.servparm & SERVSIG_ADDR) )
421 sysblk.servparm =
422 APPLY_PREFIXING (sysblk.servparm, regs->PX);
423
424 if (CPU_STEPPING_OR_TRACING_ALL)
425 {
426 logmsg (_("HHCCP027I External interrupt: Service signal %8.8X\n"),
427 sysblk.servparm);
428 }
429
430 /* Store service signal parameter at PSA+X'80' */
431 psa = (void*)(regs->mainstor + regs->PX);
432 STORE_FW(psa->extparm,sysblk.servparm);
433
434 } /* end switch(sysblk.servcode) */
435 /* Reset service parameter */
436 sysblk.servparm = 0;
437
438 /* Reset service code */
439 sysblk.servcode = 0;
440
441 /* Reset service signal pending */
442 OFF_IC_SERVSIG;
443
444 /* Generate service signal interrupt */
445 ARCH_DEP(external_interrupt) (servcode, regs);
446
447 #else /* defined(FEATURE_VM_BLOCKIO) */
448
449 /* Apply prefixing if the parameter is a storage address */
450 if ( (sysblk.servparm & SERVSIG_ADDR) )
451 sysblk.servparm =
452 APPLY_PREFIXING (sysblk.servparm, regs->PX);
453
454 if (CPU_STEPPING_OR_TRACING_ALL)
455 {
456 logmsg (_("HHCCP027I External interrupt: Service signal %8.8X\n"),
457 sysblk.servparm);
458 }
459
460 /* Store service signal parameter at PSA+X'80' */
461 psa = (void*)(regs->mainstor + regs->PX);
462 STORE_FW(psa->extparm,sysblk.servparm);
463
464 /* Reset service parameter */
465 sysblk.servparm = 0;
466
467 /* Reset service signal pending */
468 OFF_IC_SERVSIG;
469
470 /* Generate service signal interrupt */
471 ARCH_DEP(external_interrupt) (EXT_SERVICE_SIGNAL_INTERRUPT, regs);
472
473 #endif /* defined(FEATURE_VM_BLOCKIO) */
474
475 } /* end OPEN_IC_SERVSIG(regs) */
476
477 } /* end function perform_external_interrupt */
478
479
480 /*-------------------------------------------------------------------*/
481 /* Store Status */
482 /* Input: */
483 /* sregs Register context of CPU whose status is to be stored */
484 /* aaddr A valid absolute address of a 512-byte block into */
485 /* which status is to be stored */
486 /* For an implicit store status, or an operator */
487 /* initiated store status the absolute address will be */
488 /* zero, for a store status at address order the */
489 /* supplied address will be nonzero */
490 /*-------------------------------------------------------------------*/
ARCH_DEP(store_status)491 void ARCH_DEP(store_status) (REGS *ssreg, RADR aaddr)
492 {
493 int i; /* Array subscript */
494 PSA *sspsa; /* -> Store status area */
495
496 /* Set reference and change bits */
497 STORAGE_KEY(aaddr, ssreg) |= (STORKEY_REF | STORKEY_CHANGE);
498 #if defined(FEATURE_ESAME)
499 /* The ESAME PSA is two pages in size */
500 if(!aaddr)
501 STORAGE_KEY(aaddr + 4096, ssreg) |= (STORKEY_REF | STORKEY_CHANGE);
502 #endif /*defined(FEATURE_ESAME)*/
503
504 #if defined(FEATURE_ESAME)
505 /* For store status at address, we must adjust the PSA offset */
506 /* ZZ THIS TEST IS NOT CONCLUSIVE */
507 if(aaddr != 0 && aaddr != ssreg->PX)
508 aaddr -= 512 + 4096 ;
509 #endif
510
511 aaddr &= 0x7FFFFE00;
512
513 /* Point to the PSA into which status is to be stored */
514 sspsa = (void*)(ssreg->mainstor + aaddr);
515
516 /* Store CPU timer in bytes 216-223 */
517 STORE_DW(sspsa->storeptmr, cpu_timer(ssreg));
518
519 /* Store clock comparator in bytes 224-231 */
520 #if defined(FEATURE_ESAME)
521 STORE_DW(sspsa->storeclkc, ssreg->clkc);
522 #else /*defined(FEATURE_ESAME)*/
523 STORE_DW(sspsa->storeclkc, ssreg->clkc << 8);
524 #endif /*defined(FEATURE_ESAME)*/
525
526 /* Store PSW in bytes 256-263 */
527 ARCH_DEP(store_psw) (ssreg, sspsa->storepsw);
528
529 /* Store prefix register in bytes 264-267 */
530 STORE_FW(sspsa->storepfx,ssreg->PX);
531
532 #if defined(FEATURE_ESAME)
533 /* Store Floating Point Control Register */
534 STORE_FW(sspsa->storefpc,ssreg->fpc);
535
536 /* Store TOD Programable register */
537 STORE_FW(sspsa->storetpr,ssreg->todpr);
538 #endif /*defined(FEATURE_ESAME)*/
539
540 #if defined(_900)
541 /* Only store the arch mode indicator for a PSA type store status */
542 if(!aaddr)
543 #if defined(FEATURE_ESAME)
544 sspsa->arch = 1;
545 #else /*defined(FEATURE_ESAME)*/
546 sspsa->arch = 0;
547 #endif /*defined(FEATURE_ESAME)*/
548 #endif /*defined(_900)*/
549
550 /* Store access registers in bytes 288-351 */
551 for (i = 0; i < 16; i++)
552 STORE_FW(sspsa->storear[i],ssreg->AR(i));
553
554 /* Store floating-point registers in bytes 352-383 */
555 #if defined(FEATURE_ESAME)
556 for (i = 0; i < 32; i++)
557 #else /*!defined(FEATURE_ESAME)*/
558 for (i = 0; i < 8; i++)
559 #endif /*!defined(FEATURE_ESAME)*/
560 STORE_FW(sspsa->storefpr[i],ssreg->fpr[i]);
561
562 /* Store general-purpose registers in bytes 384-447 */
563 for (i = 0; i < 16; i++)
564 STORE_W(sspsa->storegpr[i],ssreg->GR(i));
565
566 /* Store control registers in bytes 448-511 */
567 for (i = 0; i < 16; i++)
568 STORE_W(sspsa->storecr[i],ssreg->CR(i));
569
570 } /* end function store_status */
571
572
573 #if !defined(_GEN_ARCH)
574
575 #if defined(_ARCHMODE2)
576 #define _GEN_ARCH _ARCHMODE2
577 #include "external.c"
578 #endif
579
580 #if defined(_ARCHMODE3)
581 #undef _GEN_ARCH
582 #define _GEN_ARCH _ARCHMODE3
583 #include "external.c"
584 #endif
585
586
store_status(REGS * ssreg,U64 aaddr)587 void store_status (REGS *ssreg, U64 aaddr)
588 {
589 switch(ssreg->arch_mode) {
590 #if defined(_370)
591 case ARCH_370:
592 aaddr &= 0x7FFFFFFF;
593 s370_store_status (ssreg, aaddr);
594 break;
595 #endif
596 #if defined(_390)
597 case ARCH_390:
598 aaddr &= 0x7FFFFFFF;
599 s390_store_status (ssreg, aaddr);
600 break;
601 #endif
602 #if defined(_900)
603 case ARCH_900:
604 z900_store_status (ssreg, aaddr);
605 break;
606 #endif
607 }
608 }
609 #endif /*!defined(_GEN_ARCH)*/
610