1 /* VM.C (c) Copyright Roger Bowler, 2000-2009 */
2 /* ESA/390 VM Diagnose calls and IUCV instruction */
3
4 /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */
5
6 /*-------------------------------------------------------------------*/
7 /* This module implements miscellaneous diagnose functions */
8 /* described in SC24-5670 VM/ESA CP Programming Services */
9 /* and SC24-5855 VM/ESA CP Diagnosis Reference */
10 /* and SC24-6084 z/VM 5.4 CP Programming Services. */
11 /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */
12 /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */
13 /*-------------------------------------------------------------------*/
14
15 #include "hstdinc.h"
16
17 #if !defined(_HENGINE_DLL_)
18 #define _HENGINE_DLL_
19 #endif /*_HENGINE_DLL_*/
20
21 #if !defined(_VM_C_)
22 #define _VM_C_
23 #endif /* _VM_C_ */
24
25 #include "hercules.h"
26 #include "opcode.h"
27 #include "inline.h"
28 #include "commadpt.h"
29
30 #if defined(FEATURE_EMULATE_VM)
31
32 #if !defined(_VM_C)
33 #define _VM_C
34
35 /*-------------------------------------------------------------------*/
36 /* Internal macro definitions */
37 /*-------------------------------------------------------------------*/
38 #define DEV024(_type,_cls,_typ) \
39 { _type,_cls,_typ,0xC0 }
40 #define DEV210(_type,_cls,_typ) \
41 { _type,_cls,_typ,0x40 }
42
43 /*-------------------------------------------------------------------*/
44 /* Synchronous Block I/O Parameter List */
45 /*-------------------------------------------------------------------*/
46 typedef struct _HCPSBIOP {
47 HWORD devnum; /* Device number */
48 BYTE akey; /* Bits 0-3=key, 4-7=zeroes */
49 BYTE type; /* I/O request type */
50 FWORD blksize; /* Fixed block size */
51 FWORD sbiaddr; /* Address of SBILIST */
52 FWORD sbicount; /* Number of SBILIST entries */
53 FWORD blkcount; /* Number of blocks processed*/
54 BYTE unitstat; /* Device status */
55 BYTE chanstat; /* Subchannel status */
56 HWORD residual; /* Residual byte count */
57 BYTE lpm; /* Logical path mask */
58 BYTE resv1[5]; /* Reserved bytes, must be 0 */
59 HWORD sensecount; /* Number of sense bytes */
60 BYTE resv2[24]; /* Reserved bytes, must be 0 */
61 BYTE sense[32]; /* Sense bytes */
62 } HCPSBIOP;
63
64 /* Definitions for I/O request type */
65 #define HCPSBIOP_WRITE 0x01
66 #define HCPSBIOP_READ 0x02
67
68 /*-------------------------------------------------------------------*/
69 /* Synchronous General I/O Parameter List */
70 /*-------------------------------------------------------------------*/
71 typedef struct _HCPSGIOP {
72 HWORD devnum; /* Device number */
73 BYTE akey; /* Bits 0-3=key, 4-7=zeroes */
74 BYTE flag; /* Flags */
75 FWORD resv1; /* Reserved word, must be 0 */
76 FWORD ccwaddr; /* Address of channel program*/
77 FWORD resv2; /* Reserved word, must be 0 */
78 FWORD lastccw; /* CCW address at interrupt */
79 BYTE unitstat; /* Device status */
80 BYTE chanstat; /* Subchannel status */
81 HWORD residual; /* Residual byte count */
82 BYTE lpm; /* Logical path mask */
83 BYTE resv3[5]; /* Reserved bytes, must be 0 */
84 HWORD sensecount; /* Number of sense bytes */
85 BYTE resv4[24]; /* Reserved bytes, must be 0 */
86 BYTE sense[32]; /* Sense bytes */
87 } HCPSGIOP;
88
89 /* Bit definitions for flags */
90 #define HCPSGIOP_FORMAT1_CCW 0x80 /* 1=Format-1 CCW */
91 #define HCPSGIOP_FLAG_RESV 0x7F /* Reserved bits, must be 0 */
92
93 /*-------------------------------------------------------------------*/
94 /* DIAGNOSE X'24' and DIAGNOSE X'210' Structures and Table */
95 /*-------------------------------------------------------------------*/
96
97 /* VM Device Class Definitions */
98 #define DC_TERM 0x80
99 #define DC_GRAF 0x40
100 #define DC_URI 0x20
101 #define DC_URO 0x10
102 #define DC_TAPE 0x08
103 #define DC_DASD 0x04
104 #define DC_SPEC 0x02
105 #define DC_FBA 0x01
106
107 /* VM Device Type Definitions */
108 #define DT_CTCA 0x80
109 #define DT_FBA 0x00
110 #define DT_OSA 0x20 /* Not yet supported */
111 #define DT_UNKN 0x01
112 #define DT_0671 0x20
113 #define DT_1052 0x00
114 #define DT_1403 0x41
115 #define DT_1442 0x88
116 #define DT_2305 0x02
117 #define DT_2311 0x80
118 #define DT_2314 0x40
119 #define DT_2501 0x81
120 #define DT_2703 0x40
121 #define DT_3211 0x42
122 #define DT_3215 0x00
123 #define DT_3277 0x04
124 #define DT_3287 0x02
125 #define DT_3310 0x01
126 #define DT_3330 0x10
127 #define DT_3340 0x01
128 #define DT_3350 0x08
129 #define DT_3370 0x02
130 #define DT_3375 0x04
131 #define DT_3380 0x20
132 #define DT_3390 0x82
133 #define DT_3410 0x08
134 #define DT_3420 0x10
135 #define DT_3422 0x82
136 #define DT_3430 0x02
137 #define DT_3480 0x01
138 #define DT_3490 0x81
139 #define DT_3505 0x84
140 #define DT_3525 0x84
141 #define DT_3590 0x83
142 #define DT_370x 0x40
143 #define DT_8809 0x04
144 #define DT_9332 0x08
145 #define DT_9335 0x04
146 #define DT_9336 0x40
147 #define DT_9345 0x81
148 #define DT_9347 0x84
149
150 /* VM Virtual Device Status Definitions */
151 #define DS_DED 0x01 /* Dedicated device */
152 #define DS_BUSY 0x20 /* Device is busy */
153
154 /* VM Virtual Device Flag Definitions */
155 #define DF_ENA 0x80 /* 270x line enabled */
156 #define DF_CONN 0x40 /* 270x line connected */
157 #define DF_RSRL 0x02 /* Reserve/Release supported */
158 #define DF_MIDAW 0x01 /* MIDAW's supported */
159
160 /* VM Real Device Features */
161 #define DRF_RPS 0x80 /* Device has RPS */
162 #define DRF_EXTSNS 0x40 /* Extended Sense */
163 #define DRF_CTCA 0x40 /* CTCA device */
164 #define DRF_35M 0x08 /* 3340 has 35M data module */
165 #define DRF_70M 0x04 /* 3340 has 70M data module */
166 #define DRF_RSRL 0x02 /* Reserve/Release valid */
167
168 /*-------------------------------------------------------------------*/
169 /* Hercules-to-VM Device Table */
170 /*-------------------------------------------------------------------*/
171 typedef struct _VMDEVTBL {
172 U16 vmhtype; /* Hercules device type */
173 BYTE vmdevcls; /* VM Device Class */
174 BYTE vmdevtyp; /* VM Device Type */
175 BYTE vmdiags; /* DIAGS recognizing device */
176 #define VMDIAG024 0x80 /* Device recognized by DIAGNOSE X'24' */
177 #define VMDIAG210 0x40 /* Device recognized by DIAGNOSE X'210' */
178 } VMDEVTBL;
179 #define VMDEV_SIZE sizeof(VMDEVTBL)
180
181 static VMDEVTBL vmdev[] = {
182 DEV024(0x0671,DC_FBA, DT_0671),
183 DEV024(0x1052,DC_TERM,DT_1052),
184 DEV024(0x1403,DC_URO, DT_1403),
185 DEV024(0x1442,DC_URI, DT_1442),
186 DEV024(0x2305,DC_DASD,DT_2305),
187 DEV024(0x2311,DC_DASD,DT_2311),
188 DEV024(0x2314,DC_DASD,DT_2314),
189 DEV024(0x2501,DC_URI, DT_2501),
190 DEV024(0x2703,DC_TERM,DT_2703),
191 DEV024(0x3088,DC_SPEC,DT_CTCA),
192 DEV024(0x3211,DC_URI, DT_3211),
193 DEV024(0x3215,DC_TERM,DT_3215),
194 DEV024(0x3270,DC_GRAF,DT_3277),
195 DEV024(0x3287,DC_GRAF,DT_3287),
196 DEV024(0x3310,DC_FBA, DT_3310),
197 DEV024(0x3330,DC_DASD,DT_3330),
198 DEV024(0x3340,DC_DASD,DT_3340),
199 DEV024(0x3350,DC_DASD,DT_3350),
200 DEV024(0x3370,DC_FBA, DT_3370),
201 DEV024(0x3375,DC_DASD,DT_3375),
202 DEV024(0x3380,DC_DASD,DT_3380),
203 DEV210(0x3390,DC_DASD,DT_3390),
204 DEV024(0x3410,DC_TAPE,DT_3410),
205 DEV024(0x3420,DC_TAPE,DT_3420),
206 DEV024(0x3422,DC_TAPE,DT_3422),
207 DEV024(0x3430,DC_TAPE,DT_3430),
208 DEV024(0x3480,DC_TAPE,DT_3480),
209 DEV210(0x3490,DC_TAPE,DT_3490),
210 DEV024(0x3505,DC_URI, DT_3505),
211 DEV024(0x3525,DC_URO, DT_3525),
212 DEV024(0x3590,DC_TAPE,DT_3590),
213 DEV024(0x3705,DC_SPEC,DT_370x),
214 DEV024(0x8809,DC_TAPE,DT_8809),
215 DEV024(0x9332,DC_FBA, DT_9332),
216 DEV024(0x9335,DC_FBA, DT_9335),
217 DEV024(0x9336,DC_FBA, DT_9336),
218 DEV210(0x9345,DC_DASD,DT_9345),
219 DEV024(0x9347,DC_TAPE,DT_9347)
220 };
221 #define VMDEV_NUM (sizeof(vmdev)/VMDEV_SIZE)
222
223 /*-------------------------------------------------------------------*/
224 /* Virtual Device Data */
225 /*-------------------------------------------------------------------*/
226 typedef struct _VRDCVDAT {
227 BYTE vdevcls; /* Virtual device class */
228 BYTE vdevtyp; /* Virtual device type */
229 BYTE vdevstat; /* Virtual device status */
230 BYTE vdevflag; /* Virtual device flag */
231 } VRDCVDAT;
232
233 /*-------------------------------------------------------------------*/
234 /* Real Device Data */
235 /*-------------------------------------------------------------------*/
236 typedef struct _VRDCRCDT {
237 BYTE rdevcls; /* Real device class */
238 BYTE rdevtyp; /* Real device type */
239 BYTE rdevmodl; /* Real device model */
240 BYTE rdevfeat; /* Real device features */
241 } VRDCRCDT;
242
243 /*-------------------------------------------------------------------*/
244 /* Virtual/Real Device Characteristics Block */
245 /*-------------------------------------------------------------------*/
246 typedef struct _VRDCBLOK {
247 /*00*/ HWORD vrdcdvno; /* Device number */
248 /*02*/ HWORD vrdclen; /* VRDCBLOK length */
249 /*04*/ VRDCVDAT vrdcvdat; /* Virtual device data */
250 /*08*/ VRDCRCDT vrdcrcdt; /* Real device data */
251 /*0C*/ BYTE vrdcundv; /* Real underlying device */
252 /*0D*/ BYTE vrdcrdaf; /* Real device additional features */
253 #define VRDCEMRD 0x02 /* No emulated real device */
254 /*0E*/ HWORD vrdcrsvd; /* Reserved - must be zeros */
255 /*10*/ BYTE vrdcrdc[64]; /* READ DEVICE CHARACTERISTICS data */
256 /*50*/ BYTE vrdcpgid[11]; /* Path Group Identifier */
257 /*5B*/ BYTE resv5[5]; /* reserved */
258 /*60*/ BYTE vrdcvers; /* version */
259 /*61*/ BYTE vrdcrsio[31]; /* reserved for Input/Output */
260 /*80*/ HWORD vrdcrdev; /* Real device number */
261 /*82*/ BYTE vrdcrsve[126]; /* reserverd */
262 /*100*/
263 } VRDCBLOK;
264 #define VRDCBLOK_SIZE sizeof(VRDCBLOK)
265
266 #endif /*!defined(_VM_C)*/
267
268 /*-------------------------------------------------------------------*/
269 /* Internal Function Prototypes */
270 /*-------------------------------------------------------------------*/
271 DEVBLK* ARCH_DEP(vmdevice_data)(int, U16, VRDCVDAT *, VRDCRCDT *);
272
273 /*-------------------------------------------------------------------*/
274 /* Provide VM Virtual and Real Device Data based upon device number */
275 /*-------------------------------------------------------------------*/
ARCH_DEP(vmdevice_data)276 DEVBLK* ARCH_DEP(vmdevice_data)(int code, U16 devnum, VRDCVDAT *vdat, VRDCRCDT *rdat)
277 {
278 U32 i; /* loop index */
279 VMDEVTBL *vmentry; /* -> VMDEVTBL entry found */
280 DEVBLK *dev; /* -> DEVBLK */
281
282 /* Clear vdat and rdat */
283 memset (vdat, 0x00, sizeof(*vdat));
284 memset (rdat, 0x00, sizeof(*rdat));
285
286 /* Locate the device block */
287 dev = find_device_by_devnum (0,devnum);
288
289 /* Return 0 if device is not found */
290 if (!dev)
291 return 0;
292
293 /* Indicate the device is dedicated - all Hercules devices are */
294 vdat->vdevstat = DS_DED;
295
296 /* Find the device in the VM table */
297 vmentry=NULL;
298 for (i = 0; i < (int)VMDEV_NUM; i++)
299 {
300 #if 0
301 logmsg ("vmdevice_data: i=%i %4.4X %2.2X %2.2X %2.2X\n",i,
302 vmdev[i].vmhtype,vmdev[i].vmdevcls,vmdev[i].vmdevtyp,vmdev[i].vmdiags);
303 #endif
304 if (dev->devtype == vmdev[i].vmhtype)
305 {
306 vmentry = &vmdev[i];
307 break;
308 }
309 }
310 #if 0
311 logmsg ("FOUND: %4.4X %2.2X %2.2X %2.2X\n",
312 vmentry->vmhtype,vmentry->vmdevcls,vmentry->vmdevtyp,vmentry->vmdiags);
313 #endif
314
315 /* If device is not in the table or it isn't recognized by DIAG X'24' */
316 if ( !vmentry || ( code==0x24 && !(vmentry->vmdiags & VMDIAG024 ) ) )
317 {
318 /* Set the real and virtual data to an unsupported device */
319 vdat->vdevcls = DC_SPEC;
320 vdat->vdevtyp = DT_UNKN;
321 rdat->rdevcls = DC_SPEC;
322 rdat->rdevtyp = DT_UNKN;
323 return dev;
324 }
325
326 /* Set the virtual and real data to the device's VM class and type */
327 vdat->vdevcls = vmentry->vmdevcls;
328 vdat->vdevtyp = vmentry->vmdevtyp;
329 rdat->rdevcls = vmentry->vmdevcls;
330 rdat->rdevtyp = vmentry->vmdevtyp;
331
332 /* Indicate if the device is busy */
333 if ( (dev->busy && dev->ioactive == DEV_SYS_LOCAL) || dev->startpending )
334 vdat->vdevstat |= DS_BUSY;
335
336 /* Set virtual device flags, and real device model and features */
337 vdat->vdevflag = 0x00;
338 rdat->rdevmodl = 0x00;
339 rdat->rdevfeat = 0x00;
340
341 if (dev->hnd->reserve) /* Indicate if RESERVE/RELEASE supported */
342 vdat->vdevflag |= DF_RSRL;
343
344 #if defined(FEATURE_MIDAW)
345 /* If DIAGNOSE X'210', indicate if MIDAW's are supported */
346 if (code==0x210)
347 vdat->vdevflag |= DF_MIDAW;
348 #endif /* FEATURE_MIDAW */
349
350 switch (rdat->rdevcls) {
351 case DC_DASD:
352 if (dev->hnd->reserve)
353 rdat->rdevfeat |= DRF_RSRL;
354 if (dev->numsense==24)
355 rdat->rdevfeat |= DRF_EXTSNS;
356 if (dev->ckdtab->sectors)
357 rdat->rdevfeat |= DRF_RPS;
358 if (dev->devtype == 0x3340)
359 {
360 if (dev->ckdtab->model==0x01)
361 rdat->rdevfeat |= DRF_35M;
362 else
363 rdat->rdevfeat |= DRF_70M;
364 }
365 if ( dev->devtype == 0x3380 && code == 0x24)
366 rdat->rdevmodl = (dev->ckdtab->model & 0x0F) | (dev->ckdcu->model & 0xF0);
367 else
368 rdat->rdevmodl = dev->ckdtab->model;
369 break;
370 case DC_FBA:
371 rdat->rdevmodl = dev->fbatab->model;
372 break;
373 case DC_TERM:
374 if (dev->devtype==0x3215)
375 {
376 rdat->rdevfeat = 0x50;
377 /* Note: 0x50 is carried forward from the previous version of */
378 /* DIAGNOSE X'24'. The actual meaning was not previously documented */
379 }
380 else
381 {
382 if (dev->devtype==0x2703 && dev->commadpt)
383 {
384 if (dev->commadpt->enabled)
385 vdat->vdevflag |= DF_ENA;
386 if (dev->commadpt->connect)
387 vdat->vdevflag |= DF_CONN;
388 }
389 }
390 break;
391 case DC_SPEC:
392 if (rdat->rdevtyp==DT_CTCA)
393 rdat->rdevfeat = DRF_CTCA;
394 }
395
396 /* Return the located DEVBLK to the caller */
397 return dev;
398
399 } /* end function vmdevice_data */
400
401 /*-------------------------------------------------------------------*/
402 /* Device Type and Features (Function code 0x024) */
403 /*-------------------------------------------------------------------*/
ARCH_DEP(diag_devtype)404 int ARCH_DEP(diag_devtype) (int r1, int r2, REGS *regs)
405 {
406 DEVBLK *dev; /* -> Device block */
407 U16 devnum; /* Device number */
408 VRDCVDAT vdat; /* Virtual device data */
409 VRDCRCDT rdat; /* Real device data */
410
411 #if defined(FEATURE_ESAME)
412 /* Program check if 64-bit addressing is being used. */
413 if (regs->psw.amode64)
414 {
415 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
416 }
417 #endif /* FEATURE_ESAME */
418
419 /* Return console information if R1 register is all ones */
420 if (regs->GR_L(r1) == 0xFFFFFFFF)
421 {
422 for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
423 if ( dev->allocated
424 && ( dev->devtype == 0x3215 || dev->devtype == 0x1503 )
425 )
426 {
427 regs->GR_L(r1) = dev->devnum;
428 break;
429 }
430 }
431
432 /* Extract the device number from the R1 register */
433 devnum = regs->GR_L(r1);
434
435 /* Locate the device block and set the virtual and real device information */
436 dev = ARCH_DEP(vmdevice_data) (0x24,devnum,&vdat,&rdat);
437
438 /* Return condition code 3 if device does not exist */
439 if (!dev)
440 return 3;
441
442 /* Return virtual device information in the R2 register */
443 FETCH_FW(regs->GR_L(r2),&vdat);
444
445 /* Return real device information in the R2+1 register */
446 if (r2 != 15)
447 FETCH_FW(regs->GR_L(r2+1),&rdat);
448 #if 0
449 logmsg ("Diagnose X\'024\':"
450 "devnum=%4.4X VRDCVDAT=%8.8X VRDCRCDT=%8.8X\n",
451 devnum, vdat, rdat);
452 #endif
453
454 /* Return condition code 0 */
455 return 0;
456
457 } /* end function diag_devtype */
458
459 /*-------------------------------------------------------------------*/
460 /* Process Synchronous Fixed Block I/O call (Function code 0x0A4) */
461 /*-------------------------------------------------------------------*/
ARCH_DEP(syncblk_io)462 int ARCH_DEP(syncblk_io) (int r1, int r2, REGS *regs)
463 {
464 U32 i; /* Array subscript */
465 U32 numsense; /* Number of sense bytes */
466 U32 iopaddr; /* Address of HCPSBIOP */
467 HCPSBIOP ioparm; /* I/O parameter list */
468 DEVBLK *dev; /* -> Device block */
469 U16 devnum; /* Device number */
470 U16 residual; /* Residual byte count */
471 U32 blksize; /* Fixed block size */
472 U32 sbiaddr; /* Addr of SBILIST */
473 U32 sbicount; /* Number of SBILIST entries */
474 U32 blkcount; /* Number of blocks processed*/
475 U32 blknum; /* Block number */
476 U32 absadr; /* Absolute storage address */
477 BYTE accum; /* Work area */
478 BYTE unitstat = 0; /* Device status */
479 BYTE chanstat = 0; /* Subchannel status */
480 BYTE skey1, skey2; /* Storage keys of first and
481 last byte of I/O buffer */
482 //FIXME: code not right for shared devices
483
484 UNREFERENCED(r2);
485
486 /* Register R1 contains the real address of the parameter list */
487 iopaddr = regs->GR_L(r1);
488
489 /* Program check if parameter list not on fullword boundary */
490 if (iopaddr & 0x00000003)
491 {
492 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
493 return 0;
494 }
495
496 /* Ensure that parameter list operand is addressable */
497 ARCH_DEP(validate_operand) (iopaddr, USE_REAL_ADDR, sizeof(ioparm)-1,
498 ACCTYPE_WRITE, regs);
499
500 /* Fetch the parameter list from real storage */
501 ARCH_DEP(vfetchc) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs);
502
503 /* Load numeric fields from the parameter list */
504 devnum = (ioparm.devnum[0] << 8) | ioparm.devnum[1];
505 blksize = (ioparm.blksize[0] << 24)
506 | (ioparm.blksize[1] << 16)
507 | (ioparm.blksize[2] << 8)
508 | ioparm.blksize[3];
509 sbiaddr = (ioparm.sbiaddr[0] << 24)
510 | (ioparm.sbiaddr[1] << 16)
511 | (ioparm.sbiaddr[2] << 8)
512 | ioparm.sbiaddr[3];
513 sbicount = (ioparm.sbicount[0] << 24)
514 | (ioparm.sbicount[1] << 16)
515 | (ioparm.sbicount[2] << 8)
516 | ioparm.sbicount[3];
517
518 /* Locate the device block */
519 dev = find_device_by_devnum (0,devnum);
520
521 /* Set return code 2 and cond code 1 if device does not exist
522 or does not support the synchronous I/O call */
523 if (dev == NULL || dev->devtype != 0x3370)
524 {
525 regs->GR_L(15) = 2;
526 return 1;
527 }
528
529 /* Program check if protect key bits 4-7 are not zero
530 or if I/O request type is not read or write */
531 if ((ioparm.akey & 0x0F)
532 || !(ioparm.type == HCPSBIOP_WRITE
533 || ioparm.type == HCPSBIOP_READ))
534 {
535 ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
536 return 0;
537 }
538
539 /* Set return code 8 and cond code 2 if blocksize is invalid */
540 if (!(blksize == 512 || blksize == 1024
541 || blksize == 2048 || blksize == 4096))
542 {
543 regs->GR_L(15) = 8;
544 return 2;
545 }
546
547 /* Program check if SBILIST is not on a doubleword boundary */
548 if (sbiaddr & 0x00000007)
549 {
550 ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
551 return 0;
552 }
553
554 /* Program check if reserved fields are not zero */
555 for (accum = 0, i = 0; i < sizeof(ioparm.resv1); i++)
556 accum |= ioparm.resv1[i];
557 for (i = 0; i < sizeof(ioparm.resv2); i++)
558 accum |= ioparm.resv2[i];
559 if (accum != 0)
560 {
561 ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
562 return 0;
563 }
564
565 /* Set return code 11 and cond code 2 if SBI count is invalid */
566 if (sbicount < 1 || sbicount > 500)
567 {
568 regs->GR_L(15) = 11;
569 return 2;
570 }
571
572 /* Obtain the device lock */
573 obtain_lock (&dev->lock);
574
575 #ifdef FEATURE_CHANNEL_SUBSYSTEM
576 /* Return code 5 and condition code 1 if status pending */
577 if ((dev->scsw.flag3 & SCSW3_SC_PEND)
578 || (dev->pciscsw.flag3 & SCSW3_SC_PEND))
579 {
580 release_lock (&dev->lock);
581 regs->GR_L(15) = 5;
582 return 1;
583 }
584 #endif /*FEATURE_CHANNEL_SUBSYSTEM*/
585
586 /* Return code 5 and condition code 1 if device is busy */
587 if (dev->busy || IOPENDING(dev))
588 {
589 release_lock (&dev->lock);
590 regs->GR_L(15) = 5;
591 return 1;
592 }
593
594 /* Set the device busy indicator */
595 dev->busy = 1;
596
597 /* Release the device lock */
598 release_lock (&dev->lock);
599
600 /* Process each entry in the SBILIST */
601 for (blkcount = 0; blkcount < sbicount; blkcount++)
602 {
603 /* Return code 10 and cond code 2 if SBILIST entry
604 is outside main storage or is fetch protected.
605 Note that the SBI address is an absolute address
606 and is not subject to fetch-protection override
607 or storage-protection override mechanisms, and
608 an SBILIST entry cannot cross a page boundary */
609 if (sbiaddr > regs->mainlim
610 || ((STORAGE_KEY(sbiaddr, regs) & STORKEY_FETCH)
611 && (STORAGE_KEY(sbiaddr, regs) & STORKEY_KEY) != ioparm.akey
612 && ioparm.akey != 0))
613 {
614 regs->GR_L(15) = 10;
615 return 2;
616 }
617
618 /* Load block number and data address from SBILIST */
619 blknum = ARCH_DEP(fetch_fullword_absolute)(sbiaddr, regs);
620 absadr = ARCH_DEP(fetch_fullword_absolute)(sbiaddr+4, regs);
621
622 if (dev->ccwtrace || dev->ccwstep)
623 {
624 logmsg ("%4.4X:Diagnose X\'0A4\':%s "
625 "blk=%8.8X adr=%8.8X len=%8.8X\n",
626 dev->devnum,
627 (ioparm.type == HCPSBIOP_WRITE ? "WRITE" : "READ"),
628 blknum, absadr, blksize);
629 }
630
631 /* Return code 12 and cond code 2 if buffer exceeds storage */
632 if (absadr > regs->mainlim - blksize)
633 {
634 regs->GR_L(15) = 12;
635 return 2;
636 }
637
638 /* Channel protection check if access key does not match
639 storage keys of buffer. Note that the buffer address is
640 an absolute address, the buffer cannot span more than two
641 pages, and the access is not subject to fetch-protection
642 override, storage-protection override, or low-address
643 protection */
644 skey1 = STORAGE_KEY(absadr, regs);
645 skey2 = STORAGE_KEY(absadr + blksize - 1, regs);
646 if (ioparm.akey != 0
647 && (
648 ((skey1 & STORKEY_KEY) != ioparm.akey
649 && ((skey1 & STORKEY_FETCH)
650 || ioparm.type == HCPSBIOP_READ))
651 || ((skey2 & STORKEY_KEY) != ioparm.akey
652 && ((skey2 & STORKEY_FETCH)
653 || ioparm.type == HCPSBIOP_READ))
654 ))
655 {
656 chanstat |= CSW_PROTC;
657 break;
658 }
659
660 /* Call device handler to read or write one block */
661 fbadasd_syncblk_io (dev, ioparm.type, blknum, blksize,
662 regs->mainstor + absadr,
663 &unitstat, &residual);
664
665 /* Set incorrect length if residual count is non-zero */
666 if (residual != 0)
667 chanstat |= CSW_IL;
668
669 /* Exit if any unusual status */
670 if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0)
671 break;
672
673 /* Point to next SBILIST entry */
674 sbiaddr += 8;
675
676 } /* end for(blkcount) */
677
678 /* Reset the device busy indicator */
679 dev->busy = 0;
680
681 /* Store the block count in the parameter list */
682 ioparm.blkcount[0] = (blkcount >> 24) & 0xFF;
683 ioparm.blkcount[1] = (blkcount >> 16) & 0xFF;
684 ioparm.blkcount[2] = (blkcount >> 8) & 0xFF;
685 ioparm.blkcount[3] = blkcount & 0xFF;
686
687 /* Store the device and subchannel status in the parameter list */
688 ioparm.unitstat = unitstat;
689 ioparm.chanstat = chanstat;
690
691 /* Store the residual byte count in the parameter list */
692 ioparm.residual[0] = (residual >> 8) & 0xFF;
693 ioparm.residual[1] = residual & 0xFF;
694
695 /* Return sense data if unit check occurred */
696 if (unitstat & CSW_UC)
697 {
698 numsense = dev->numsense;
699 if (numsense > sizeof(ioparm.sense))
700 numsense = sizeof(ioparm.sense);
701 ioparm.sensecount[0] = (numsense >> 8) & 0xFF;
702 ioparm.sensecount[1] = numsense & 0xFF;
703 memcpy (ioparm.sense, dev->sense, numsense);
704 }
705
706 /* Store the updated parameter list in real storage */
707 ARCH_DEP(vstorec) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs);
708
709 /* If I/O error occurred, set return code 13 and cond code 3 */
710 if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0)
711 {
712 regs->GR_L(15) = 13;
713 return 3;
714 }
715
716 /* Set return code 0 and cond code 0 */
717 regs->GR_L(15) = 0;
718 return 0;
719
720 } /* end function syncblk_io */
721
722 /*-------------------------------------------------------------------*/
723 /* Process Synchronous General I/O call (Function code 0x0A8) */
724 /*-------------------------------------------------------------------*/
ARCH_DEP(syncgen_io)725 int ARCH_DEP(syncgen_io) (int r1, int r2, REGS *regs)
726 {
727 U32 i; /* Array subscript */
728 U32 numsense; /* Number of sense bytes */
729 U32 iopaddr; /* Address of HCPSGIOP */
730 HCPSGIOP ioparm; /* I/O parameter list */
731 DEVBLK *dev; /* -> Device block */
732 U16 devnum; /* Device number */
733 U16 residual; /* Residual byte count */
734 U32 ccwaddr; /* Address of channel program*/
735 U32 lastccw; /* CCW address at interrupt */
736 BYTE accum; /* Work area */
737 BYTE unitstat = 0; /* Device status */
738 BYTE chanstat = 0; /* Subchannel status */
739
740 //FIXME: code not right for shared devices
741
742 UNREFERENCED(r2);
743
744 /* Register R1 contains the real address of the parameter list */
745 iopaddr = regs->GR_L(r1);
746
747 /* Program check if parameter list not on fullword boundary */
748 if (iopaddr & 0x00000003)
749 {
750 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
751 return 0;
752 }
753
754 /* Ensure that parameter list operand is addressable */
755 ARCH_DEP(validate_operand) (iopaddr, USE_REAL_ADDR, sizeof(ioparm)-1,
756 ACCTYPE_WRITE, regs);
757
758 /* Fetch the parameter list from real storage */
759 ARCH_DEP(vfetchc) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs);
760
761 /* Load numeric fields from the parameter list */
762 devnum = (ioparm.devnum[0] << 8) | ioparm.devnum[1];
763 ccwaddr = (ioparm.ccwaddr[0] << 24)
764 | (ioparm.ccwaddr[1] << 16)
765 | (ioparm.ccwaddr[2] << 8)
766 | ioparm.ccwaddr[3];
767
768 /* Locate the device block */
769 dev = find_device_by_devnum (0,devnum);
770
771 /* Set return code 1 and cond code 1 if device does not exist */
772 if (dev == NULL)
773 {
774 regs->GR_L(15) = 1;
775 return 1;
776 }
777
778 /* Program check if protect key bits 4-7 are not zero
779 or if the reserved bits in the flag byte are not zero */
780 if ((ioparm.akey & 0x0F) || (ioparm.flag & HCPSGIOP_FLAG_RESV))
781 {
782 ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
783 return 0;
784 }
785
786 #ifdef FEATURE_S370_CHANNEL
787 /* Program check if flag byte specifies format-1 CCW */
788 if (ioparm.flag & HCPSGIOP_FORMAT1_CCW)
789 {
790 ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
791 return 0;
792 }
793 #endif /*FEATURE_S370_CHANNEL*/
794
795 /* Program check if CCW is not on a doubleword boundary,
796 or if CCW address exceeds maximum according to CCW format */
797 if ((ccwaddr & 0x00000007) || ccwaddr >
798 ((ioparm.flag & HCPSGIOP_FORMAT1_CCW) ?
799 (U32)0x7FFFFFFF : (U32)0x00FFFFFF))
800 {
801 ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
802 return 0;
803 }
804
805 /* Program check if reserved fields are not zero */
806 for (accum = 0, i = 0; i < sizeof(ioparm.resv1); i++)
807 accum |= ioparm.resv1[i];
808 for (i = 0; i < sizeof(ioparm.resv2); i++)
809 accum |= ioparm.resv2[i];
810 for (i = 0; i < sizeof(ioparm.resv3); i++)
811 accum |= ioparm.resv3[i];
812 for (i = 0; i < sizeof(ioparm.resv4); i++)
813 accum |= ioparm.resv4[i];
814 if (accum != 0)
815 {
816 ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION);
817 return 0;
818 }
819
820 /* Obtain the interrupt lock */
821 obtain_lock (&dev->lock);
822
823 #ifdef FEATURE_CHANNEL_SUBSYSTEM
824 /* Return code 5 and condition code 1 if status pending */
825 if ((dev->scsw.flag3 & SCSW3_SC_PEND)
826 || (dev->pciscsw.flag3 & SCSW3_SC_PEND))
827 {
828 release_lock (&dev->lock);
829 regs->GR_L(15) = 5;
830 return 1;
831 }
832 #endif /*FEATURE_CHANNEL_SUBSYSTEM*/
833
834 /* Return code 5 and condition code 1 if device is busy */
835 if (dev->busy || IOPENDING(dev))
836 {
837 release_lock (&dev->lock);
838 regs->GR_L(15) = 5;
839 return 1;
840 }
841
842 /* Set the device busy indicator */
843 dev->busy = 1;
844
845 /* Release the device lock */
846 release_lock (&dev->lock);
847
848 /* Build the operation request block */ /*@IWZ*/
849 memset (&dev->orb, 0, sizeof(ORB)); /*@IWZ*/
850 STORE_FW(dev->orb.ccwaddr, ccwaddr); /*@IWZ*/
851 dev->orb.flag4 = ioparm.akey & ORB4_KEY; /*@IWZ*/
852 if (ioparm.flag & HCPSGIOP_FORMAT1_CCW) /*@IWZ*/
853 dev->orb.flag5 |= ORB5_F; /*@IWZ*/
854
855 /* Execute the channel program synchronously */
856 ARCH_DEP(execute_ccw_chain) (dev);
857
858 /* Obtain status, CCW address, and residual byte count */
859 #ifdef FEATURE_S370_CHANNEL
860 lastccw = (dev->csw[1] << 16) || (dev->csw[2] << 8)
861 || dev->csw[3];
862 unitstat = dev->csw[4];
863 chanstat = dev->csw[5];
864 residual = (dev->csw[6] << 8) || dev->csw[7];
865 #endif /*FEATURE_S370_CHANNEL*/
866
867 #ifdef FEATURE_CHANNEL_SUBSYSTEM
868 lastccw = (dev->scsw.ccwaddr[0] << 24)
869 || (dev->scsw.ccwaddr[1] << 16)
870 || (dev->scsw.ccwaddr[2] << 8)
871 || dev->scsw.ccwaddr[3];
872 unitstat = dev->scsw.unitstat;
873 chanstat = dev->scsw.chanstat;
874 residual = (dev->scsw.count[0] << 8) || dev->scsw.count[1];
875 #endif /*FEATURE_CHANNEL_SUBSYSTEM*/
876
877 /* Clear the interrupt pending and device busy conditions */
878 obtain_lock (&dev->lock);
879 dev->busy = dev->pending = 0;
880 dev->scsw.flag2 = 0;
881 dev->scsw.flag3 = 0;
882 release_lock (&dev->lock);
883
884 /* Store the last CCW address in the parameter list */
885 ioparm.lastccw[0] = (lastccw >> 24) & 0xFF;
886 ioparm.lastccw[1] = (lastccw >> 16) & 0xFF;
887 ioparm.lastccw[2] = (lastccw >> 8) & 0xFF;
888 ioparm.lastccw[3] = lastccw & 0xFF;
889
890 /* Store the device and subchannel status in the parameter list */
891 ioparm.unitstat = unitstat;
892 ioparm.chanstat = chanstat;
893
894 /* Store the residual byte count in the parameter list */
895 ioparm.residual[0] = (residual >> 8) & 0xFF;
896 ioparm.residual[1] = residual & 0xFF;
897
898 /* Return sense data if unit check occurred */
899 if (unitstat & CSW_UC)
900 {
901 numsense = dev->numsense;
902 if (numsense > sizeof(ioparm.sense))
903 numsense = sizeof(ioparm.sense);
904 ioparm.sensecount[0] = (numsense >> 8) & 0xFF;
905 ioparm.sensecount[1] = numsense & 0xFF;
906 memcpy (ioparm.sense, dev->sense, numsense);
907 }
908
909 /* Store the updated parameter list in real storage */
910 ARCH_DEP(vstorec) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs);
911
912 /* If I/O error occurred, set return code 13 and cond code 3 */
913 if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0)
914 {
915 regs->GR_L(15) = 13;
916 return 3;
917 }
918
919 /* Return with condition code 0 and register 15 unchanged */
920 return 0;
921
922 } /* end function syncgen_io */
923
924 /*-------------------------------------------------------------------*/
925 /* Store Extended Identification Code (Function code 0x000) */
926 /*-------------------------------------------------------------------*/
ARCH_DEP(extid_call)927 void ARCH_DEP(extid_call) (int r1, int r2, REGS *regs)
928 {
929 int i; /* Array subscript */
930 int ver, rel; /* Version and release number*/
931 U32 idaddr; /* Address of storage operand*/
932 U32 idlen; /* Length of storage operand */
933 BYTE buf[40]; /* Extended identification */
934 #if defined( HAVE_GETLOGIN_R )
935 #if !defined(LOGIN_NAME_MAX)
936 #define LOGIN_NAME_MAX 100
937 #endif
938 char unam[LOGIN_NAME_MAX+1]; /* User name */
939 #endif
940 char *puser; /* Pointer to user name */
941 BYTE c; /* Character work area */
942
943 /* Load storage operand address from R1 register */
944 idaddr = regs->GR_L(r1);
945
946 /* Program check if operand is not on a doubleword boundary */
947 if (idaddr & 0x00000007)
948 {
949 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
950 return;
951 }
952
953 /* Load storage operand length from R2 register */
954 idlen = regs->GR_L(r2);
955
956 /* Program check if operand length is invalid */
957 if (idlen < 1)
958 {
959 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
960 return;
961 }
962
963 /* Bytes 0-7 contain the system name ("HERCULES" in EBCDIC) */
964 get_lparname(buf);
965
966 /* Bytes 8-9 contain the execution environment bits */
967 buf[8] = 0x00;
968 buf[9] = 0x00;
969
970 /* Byte 10 contains the system product version number */
971 sscanf (MSTRING(VERSION), "%d.%d", &ver, &rel);
972 buf[10] = ver;
973
974 /* Byte 11 contains version number from STIDP */
975 buf[11] = sysblk.cpuid >> 56;
976
977 /* Bytes 12-13 contain MCEL length from STIDP */
978 buf[12] = (sysblk.cpuid >> 8) & 0xFF;
979 buf[13] = sysblk.cpuid & 0xFF;
980
981 /* Bytes 14-15 contain the CP address */
982 buf[14] = (regs->cpuad >> 8) & 0xFF;
983 buf[15] = regs->cpuad & 0xFF;
984
985 /* Bytes 16-23 contain the userid in EBCDIC */
986 #if defined( HAVE_GETLOGIN_R )
987 memset( unam, 0, sizeof(unam) );
988 VERIFY( getlogin_r ( unam, sizeof(unam) ) == 0 );
989 puser = unam;
990 #else
991 puser = "";
992 #endif
993 for (i = 0; i < 8; i++)
994 {
995 c = (*puser == '\0' ? SPACE : *(puser++));
996 buf[16+i] = host_to_guest(toupper(c));
997 }
998
999 /* Bytes 24-31 contain the program product bitmap */
1000 memcpy (buf+24, "\x7F\xFE\x00\x00\x00\x00\x00\x00", 8);
1001
1002 /* Bytes 32-35 contain the time zone differential */
1003 memset (buf+32, '\0', 4);
1004
1005 /* Bytes 36-39 contain version, level, and service level */
1006 buf[36] = ver;
1007 buf[37] = rel;
1008 buf[38] = 0x00;
1009 buf[39] = 0x00;
1010
1011 #if 0
1012 logmsg ("Diagnose X\'000\':"
1013 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X "
1014 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t"
1015 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X "
1016 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t"
1017 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n",
1018 buf[0], buf[1], buf[2], buf[3],
1019 buf[4], buf[5], buf[6], buf[7],
1020 buf[8], buf[9], buf[10], buf[11],
1021 buf[12], buf[13], buf[14], buf[15],
1022 buf[16], buf[17], buf[18], buf[19],
1023 buf[20], buf[21], buf[22], buf[23],
1024 buf[24], buf[25], buf[26], buf[27],
1025 buf[28], buf[29], buf[30], buf[31],
1026 buf[32], buf[33], buf[34], buf[35],
1027 buf[36], buf[37], buf[38], buf[39]);
1028 #endif
1029
1030 /* Enforce maximum length to store */
1031 if (idlen > sizeof(buf))
1032 idlen = sizeof(buf);
1033
1034 /* Store the extended identification code at operand address */
1035 ARCH_DEP(vstorec) (buf, idlen-1, idaddr, USE_REAL_ADDR, regs);
1036
1037 /* Deduct number of bytes from the R2 register */
1038 regs->GR_L(r2) -= idlen;
1039
1040 } /* end function extid_call */
1041
1042 /*-------------------------------------------------------------------*/
1043 /* Process CP command (Function code 0x008) */
1044 /*-------------------------------------------------------------------*/
ARCH_DEP(cpcmd_call)1045 int ARCH_DEP(cpcmd_call) (int r1, int r2, REGS *regs)
1046 {
1047 U32 i; /* Array subscript */
1048 U32 cc = 0; /* Condition code */
1049 U32 cmdaddr; /* Address of command string */
1050 U32 cmdlen; /* Length of command string */
1051 U32 respadr; /* Address of response buffer*/
1052 U32 maxrlen; /* Length of response buffer */
1053 U32 resplen; /* Length of actual response */
1054 BYTE cmdflags; /* Command flags */
1055 #define CMDFLAGS_REJPASSW 0x80 /* Reject password in command*/
1056 #define CMDFLAGS_RESPONSE 0x40 /* Return response in buffer */
1057 #define CMDFLAGS_REQPASSW 0x20 /* Prompt for password */
1058 #define CMDFLAGS_RESERVED 0x1F /* Reserved bits, must be 0 */
1059 char bufi[256]; /* Command buffer (ASCIIZ) */
1060 char bufo[257]; /* Command buffer (ASCIIZ) */
1061 char resp[256]; /* Response buffer (ASCIIZ) */
1062 char *dresp; /* Default response (ASCIIZ) */
1063 int freeresp; /* Flag to free resp bfr */
1064 U32 j,k;
1065
1066 /* Obtain command address from R1 register */
1067 cmdaddr = regs->GR_L(r1);
1068
1069 /* Obtain command length and flags from R2 register */
1070 cmdflags = regs->GR_L(r2) >> 24;
1071 cmdlen = regs->GR_L(r2) & 0x00FFFFFF;
1072
1073 /* Program check if invalid flags, or if command string
1074 is too long, or if response buffer is specified and
1075 registers are consecutive or either register
1076 specifies register 15 */
1077 if ((cmdflags & CMDFLAGS_RESERVED) || cmdlen > sizeof(bufi)-1
1078 || ((cmdflags & CMDFLAGS_RESPONSE)
1079 && (r1 == 15 || r2 == 15 || r1 == r2 + 1 || r2 == r1 + 1)))
1080 {
1081 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1082 return 0;
1083 }
1084
1085 /* Put machine into stopped state if command length is zero */
1086 if (cmdlen == 0)
1087 {
1088 regs->opinterv = 0;
1089 regs->cpustate = CPUSTATE_STOPPED;
1090 ON_IC_INTERRUPT(regs);
1091 return 0;
1092 }
1093
1094 /* Obtain the command string from storage */
1095 ARCH_DEP(vfetchc) (bufi, cmdlen-1, cmdaddr, USE_REAL_ADDR, regs);
1096
1097 /* Prepend '-' if noecho is requested */
1098 i=0;
1099 if(!(sysblk.diag8cmd & DIAG8CMD_ECHO))
1100 {
1101 bufo[0]='-';
1102 i=1;
1103 }
1104 /* Translate EBCDIC command to ASCII */
1105 for (j=0; j < cmdlen; i++,j++)
1106 {
1107 bufo[i] = guest_to_host(bufi[j]);
1108 }
1109 bufo[i] = '\0';
1110 dresp="";
1111 freeresp=0;
1112
1113 if(*bufo)
1114 {
1115 #ifdef FEATURE_HERCULES_DIAGCALLS
1116 int shcmd = 0;
1117 {
1118 char* p = bufo;
1119 while (*p && isspace(*p)) p++;
1120 if ((*(p+0) == 's' || *(p+0) == 'S') &&
1121 (*(p+1) == 'h' || *(p+1) == 'H') &&
1122 isspace(*(p+2))) shcmd = 1;
1123 }
1124 if ((sysblk.diag8cmd & DIAG8CMD_ENABLE)
1125 && (!shcmd || !(sysblk.shcmdopt & (SHCMDOPT_DISABLE | SHCMDOPT_NODIAG8)))
1126 )
1127 {
1128 if(sysblk.diag8cmd & DIAG8CMD_ECHO)
1129 logmsgp (_("HHCVM001I *%s* panel command issued by guest\n"), bufo);
1130 if (cmdflags & CMDFLAGS_RESPONSE)
1131 {
1132 dresp=log_capture(panel_command,bufo);
1133 if(dresp!=NULL)
1134 {
1135 freeresp=1;
1136 }
1137 else
1138 {
1139 dresp="";
1140 }
1141 }
1142 else
1143 {
1144 panel_command(bufo);
1145 if(sysblk.diag8cmd & DIAG8CMD_ECHO)
1146 logmsgp (_("HHCVM002I *%s* command complete\n"), bufo);
1147 }
1148 }
1149 else
1150 {
1151 if(sysblk.diag8cmd & DIAG8CMD_ECHO)
1152 {
1153 logmsgp (_("HHCVM005W *%s* panel command issued by guest (but disabled)\n"), bufo);
1154 }
1155 dresp=_("HHCVM003I Host command processing disabled by configuration statement");
1156 }
1157 #else
1158 dresp=_("HHCVM004E Host command processing not included in engine build");
1159 #endif
1160 }
1161
1162 /* Store the response and set length if response requested */
1163 if (cmdflags & CMDFLAGS_RESPONSE)
1164 {
1165 if(!freeresp)
1166 {
1167 strlcpy (resp, dresp, sizeof(resp));
1168 dresp=resp;
1169 }
1170 resplen = strlen(dresp);
1171 for (i = 0; i < resplen; i++)
1172 dresp[i] = host_to_guest(dresp[i]);
1173
1174 respadr = regs->GR_L(r1+1);
1175 maxrlen = regs->GR_L(r2+1);
1176
1177 i=(resplen<=maxrlen) ? resplen : maxrlen;
1178 j=0;
1179 while(i>0)
1180 {
1181 k=(i<255 ? i : 255);
1182 ARCH_DEP(vstorec) (&dresp[j], k-1 , respadr+j, USE_REAL_ADDR, regs);
1183 i-=k;
1184 j+=k;
1185 }
1186 regs->GR_L(r2+1) = (resplen<=maxrlen) ? resplen : resplen-maxrlen;
1187 cc = (resplen<=maxrlen) ? 0 : 1;
1188 }
1189 if(freeresp)
1190 {
1191 free(dresp);
1192 }
1193
1194 /* Set R2 register to CP completion code */
1195 regs->GR_L(r2) = 0;
1196
1197 /* Return condition code */
1198 return cc;
1199
1200 } /* end function cpcmd_call */
1201
1202 /*-------------------------------------------------------------------*/
1203 /* Access Re-IPL data (Function code 0x0B0) */
1204 /*-------------------------------------------------------------------*/
ARCH_DEP(access_reipl_data)1205 void ARCH_DEP(access_reipl_data) (int r1, int r2, REGS *regs)
1206 {
1207 U32 bufadr; /* Real addr of data buffer */
1208 U32 buflen; /* Length of data buffer */
1209
1210 /* Obtain buffer address and length from R1 and R2 registers */
1211 bufadr = regs->GR_L(r1);
1212 buflen = regs->GR_L(r2);
1213
1214 /* Program check if buffer length is negative */
1215 if ((S32)buflen < 0)
1216 {
1217 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1218 return;
1219 }
1220
1221 /* Store IPL information if buffer length is non-zero */
1222 if (buflen > 0)
1223 {
1224 /* Store one byte of zero to indicate no IPL information */
1225 ARCH_DEP(vstoreb) (0, bufadr, USE_REAL_ADDR, regs);
1226 }
1227
1228 PTT(PTT_CL_ERR,"*DIAG0B0",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
1229
1230 /* Return code 4 means no re-IPL information available */
1231 regs->GR_L(r2) = 4;
1232
1233 } /* end function access_reipl_data */
1234
1235 /*-------------------------------------------------------------------*/
1236 /* Access Device Information (Function code 0x210) */
1237 /*-------------------------------------------------------------------*/
1238 /* Note: This implementation emulates z/VM 5.4 */
ARCH_DEP(device_info)1239 int ARCH_DEP(device_info) (int r1, int r2, REGS *regs)
1240 {
1241 DEVBLK *dev; /* -> Device block */
1242 VRDCBLOK vrdc; /* VRDCBLOK */
1243 RADR blokaddr; /* Location of the VRDCBLOK */
1244 U16 bloklen; /* Length from the VRDCBLOK */
1245 #if 0
1246 /* Only required if implementation is for the z/VM 5.3 level */
1247 U16 reserved; /* Bytes 14 and 15 */
1248 #endif
1249 U16 devnum; /* Device number from the VRDCBLOK */
1250
1251
1252 UNREFERENCED(r2);
1253
1254 if (regs->GR_L(r1) & 0x3
1255 #if defined(FEATURE_ESAME)
1256 || (regs->psw.amode64)
1257 #endif /* FEATURE_ESAME */
1258 )
1259 {
1260 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1261 }
1262
1263 blokaddr = regs->GR_L(r1);
1264
1265 /* Fetch the first 4 bytes of the VRDCBLOK */
1266 ARCH_DEP(vfetchc) (&vrdc, 3, blokaddr, USE_REAL_ADDR, regs);
1267
1268 /* Get the VRDCBLOK length from the working VRDC */
1269 FETCH_HW(bloklen,&vrdc.vrdclen);
1270
1271 /* VRDCBLOK length must be at least 8 bytes */
1272 if (bloklen<8)
1273 {
1274 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1275 }
1276
1277 /* Fetch remainder of supplied VRDCBLOK, but no more */
1278 if (bloklen>VRDCBLOK_SIZE)
1279 bloklen=VRDCBLOK_SIZE;
1280 ARCH_DEP(vfetchc) (&vrdc.vrdcvdat,bloklen-5,blokaddr+4, USE_REAL_ADDR, regs);
1281
1282 #if 0
1283 /* If length is 16 or greater, bytes 14 and 15 must be zero on z/VM 5.3.0 or earlier */
1284 if ( bloklen>=16)
1285 {
1286 FETCH_HW(reserved,&vrdc.vrdcrsvd);
1287 if (reserved != 0)
1288 {
1289 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1290 }
1291 }
1292 #endif
1293
1294 /* Get the device number from the working VRDC */
1295 FETCH_HW(devnum,&vrdc.vrdcdvno);
1296
1297 /* Locate the device block and set the virtual and real device information */
1298 dev = ARCH_DEP(vmdevice_data) (0x210,devnum,&vrdc.vrdcvdat,&vrdc.vrdcrcdt);
1299
1300 /* Return condition code 3 if device does not exist */
1301 if (!dev)
1302 {
1303 PTT(PTT_CL_ERR,"*DIAG210",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
1304 return 3;
1305 }
1306
1307 /* Set the underlying device and real device features */
1308 vrdc.vrdcundv=0x00;
1309 vrdc.vrdcrdaf=0x00;
1310
1311 /* Create device dependent mappings */
1312 if (vrdc.vrdcvdat.vdevcls == DC_DASD)
1313 {
1314 memcpy(&vrdc.vrdcrdc,dev->devchar,42);
1315 switch (dev->devtype)
1316 {
1317 case 0x2311:
1318 case 0x2314:
1319 case 0x2305:
1320 case 0x3330:
1321 case 0x3340:
1322 case 0x3350:
1323 /* Set non-keyed overhead */
1324 STORE_HW(&vrdc.vrdcrdc[0x18],dev->ckdtab->f2);
1325 /* Set keyed overhead */
1326 STORE_HW(&vrdc.vrdcrdc[0x1A],dev->ckdtab->f1);
1327 /* Note: for all other DASD devices these fields contain bytes 24-27 of the RDC */
1328 }
1329 /* Set Control Unit ID */
1330 vrdc.vrdcrdc[0x2A]=dev->devchar[56];
1331 }
1332 else if (vrdc.vrdcvdat.vdevcls == DC_FBA)
1333 memcpy(&vrdc.vrdcrdc,dev->devchar,32);
1334
1335 /* Set Path Group ID */
1336 memcpy(&vrdc.vrdcpgid,dev->pgid,11);
1337
1338 /* Set version */
1339 if (bloklen>0x60)
1340 vrdc.vrdcvers=0x01;
1341
1342 /* Set underlying real device */
1343 if (!(vrdc.vrdcrdaf & VRDCEMRD))
1344 memcpy(&vrdc.vrdcrdev,&vrdc.vrdcdvno,2);
1345
1346 /* Update the VRDC in main storage */
1347 ARCH_DEP(vstorec) (&vrdc, bloklen-1, blokaddr, USE_REAL_ADDR, regs);
1348
1349 /* Return condition code 0 for success */
1350 return 0;
1351
1352 } /* end function device_info */
1353
1354
1355 /*-------------------------------------------------------------------*/
1356 /* Access Certain Virtual Machine Information (Function code 0x260) */
1357 /*-------------------------------------------------------------------*/
1358 /* Note: This implementation emulates z/VM 5.4 */
ARCH_DEP(vm_info)1359 void ARCH_DEP(vm_info) (int r1, int r2, REGS *regs)
1360 {
1361 DEVBLK *dev; /* -> Device block */
1362 U16 devnum; /* Device number */
1363 #if defined(FEATURE_ESAME)
1364 RADR stgarea; /* Storage extent area */
1365 S64 stglen; /* Storage extent area length */
1366 #endif /* FEATURE_ESAME */
1367
1368 /* Ry contains the subcode */
1369 switch(regs->GR_L(r2))
1370 {
1371 case 0x00000000: /* Highest addressable byte */
1372 #if defined(FEATURE_ESAME)
1373
1374 /* Program check if running in z/Architecture mode and */
1375 /* 64-bit addressing is being used. */
1376 if (regs->psw.amode64)
1377 {
1378 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1379 }
1380 #endif /* FEATURE_ESAME */
1381 regs->GR_L(r1) = regs->mainlim; /* provide highest addressable byte */
1382 return;
1383
1384 case 0x00000004: /* Provide BYUSER ID value */
1385
1386 /* Program check if Rx and Ry are the same registers or */
1387 /* or Ry is not an even register or the address provided */
1388 /* in Rx is not on a doubleword boundary or if running */
1389 /* in z/Architecture mode and 64-bit addressing is being used. */
1390 if ( r1 == r2 || r2 & 0x1 || regs->GR_L(r1) & 0x7
1391 #if defined(FEATURE_ESAME)
1392 || (regs->psw.amode64)
1393 #endif /* FEATURE_ESAME */
1394 )
1395 {
1396 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1397 }
1398 regs->GR_L(r2+1)=0x4; /* Indicate no BYUSER ID for Hercules */
1399 return;
1400
1401 case 0x00000008: /* Return number of lines per page */
1402 #if defined(FEATURE_ESAME)
1403
1404 /* Program check if running in z/Architecture mode and */
1405 /* 64-bit addressing is being used. */
1406 if (regs->psw.amode64)
1407 {
1408 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1409 }
1410 #endif /* FEATURE_ESAME */
1411
1412 /* Get the device number from the Rx register */
1413 devnum=regs->GR_LHL(r1);
1414
1415 /* Locate the device block */
1416 dev = find_device_by_devnum(0,devnum);
1417
1418 /* Set 0 lines per page for a valid printer or console (meaning SPOOL is OFF) */
1419 if (dev != NULL &&
1420 (dev->devtype == 0x1403 ||
1421 dev->devtype == 0x3211 ||
1422 dev->devtype == 0x1052 ||
1423 dev->devtype == 0x3215 )
1424 )
1425 {
1426 regs->GR_L(r1) = 0; /* Set zero lines per page */
1427 regs->GR_L(r2) = 0; /* Set return code to indicate a valid device */
1428 }
1429 else
1430 {
1431 regs->GR_L(r2) = 4; /* Set return code to indicate an invalid device */
1432 }
1433 return;
1434
1435 #if defined(FEATURE_ESAME)
1436 case 0x0000000C: /* Return highest addressable byte for z/Architecture machine */
1437 regs->GR_G(r1) = regs->mainlim;
1438 regs->GR_G(r2) = regs->mainlim;
1439 return;
1440
1441 case 0x00000010: /* Set storage extent */
1442
1443 /* Obtain the storage extent area real address from Rx */
1444 /* and its length from Rx+1 */
1445 stgarea=regs->GR_G(r1);
1446 stglen=regs->GR_G(r1+1); /* Length is treated as a signed value */
1447
1448 /* Program check if Rx is not an even register or the address */
1449 /* provided in Rx is not on a quadword boundary or the length */
1450 /* provided in Rx+1 is not positive or not a multiple of 16 */
1451 if ( r1 & 1 || stgarea & 0xF || stglen <= 0 || stglen & 0xF )
1452 {
1453 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1454 }
1455
1456 /* Convert real addres to absolute address */
1457 stgarea=APPLY_PREFIXING(stgarea,regs->PX );
1458
1459 /* Check to ensure extent information can be stored */
1460 if (stgarea > regs->mainlim - 16)
1461 {
1462 regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION);
1463 }
1464 /* Set start of storage extent to zero */
1465 ARCH_DEP(store_doubleword_absolute)(0,stgarea,regs);
1466 /* Set end of storage extent to last addressable byte of main storage */
1467 ARCH_DEP(store_doubleword_absolute)(regs->mainlim,stgarea+8,regs);
1468 /* Set number of extents to 1 in Ry */
1469 regs->GR_G(r2) = 1;
1470 /* Indicate all extents returned */
1471 regs->psw.cc = 0;
1472 return;
1473 #endif /* FEATURE_ESAME */
1474
1475 default: /* Invalid subcode */
1476 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1477 }
1478 }
1479
1480
1481 /*-------------------------------------------------------------------*/
1482 /* Pseudo Timer Extended (Function code 0x270) */
1483 /* Pseudo Timer (Function code 0x00C) */
1484 /*-------------------------------------------------------------------*/
ARCH_DEP(pseudo_timer)1485 void ARCH_DEP(pseudo_timer) (U32 code, int r1, int r2, REGS *regs)
1486 {
1487 int i; /* Array subscript */
1488 time_t timeval; /* Current time */
1489 struct tm *tmptr; /* -> Current time structure */
1490 U32 bufadr; /* Real addr of data buffer */
1491 U32 buflen; /* Length of data buffer */
1492 char buf[64]; /* Response buffer */
1493 BYTE dattim[64]; /* Date and time (EBCDIC) */
1494 #define DIAG_DATEFMT_SHORT 0x80 /* Date format mm/dd/yy */
1495 #define DIAG_DATEFMT_FULL 0x40 /* Date format mm/dd/yyyy */
1496 #define DIAG_DATEFMT_ISO 0x20 /* Date format yyyy-mm-dd */
1497 #define DIAG_DATEFMT_SYSDFLT 0x10 /* System-wide default format*/
1498 static char timefmt[]="%m/%d/%y%H:%M:%S%m/%d/%Y%Y-%m-%d";
1499
1500 /* Get the current date and time in EBCDIC */
1501 timeval = time(NULL);
1502 tmptr = localtime(&timeval);
1503 strftime((char *)dattim, sizeof(dattim), timefmt, tmptr);
1504 for (i = 0; dattim[i] != '\0'; i++)
1505 dattim[i] = host_to_guest(dattim[i]);
1506
1507 /* Obtain buffer address and length from R1 and R2 registers */
1508 bufadr = regs->GR_L(r1);
1509 buflen = regs->GR_L(r2);
1510
1511 /* Use length 32 if R2 is zero or function code is 00C */
1512 if (r2 == 0 || code == 0x00C)
1513 buflen = 32;
1514
1515 /* Program check if R1 and R2 specify the same non-zero
1516 register number, or if buffer length is less than or
1517 equal to zero, or if buffer address is zero, or if
1518 buffer is not on a doubleword boundary */
1519 if ((r2 != 0 && r2 == r1)
1520 || (S32)buflen <= 0
1521 || bufadr == 0
1522 || (bufadr & 0x00000007))
1523 {
1524 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1525 return;
1526 }
1527
1528 /* Build the response buffer */
1529 memset (buf, 0x00, sizeof(buf));
1530 /* Bytes 0-7 contain the date as EBCDIC MM/DD/YY */
1531 memcpy (buf, dattim, 8);
1532 /* Bytes 8-15 contain the time as EBCDIC HH:MM:SS */
1533 memcpy (buf+8, dattim+8, 8);
1534 /* Bytes 16-23 contain the virtual CPU time used in microseconds */
1535 /* Bytes 24-31 contain the total CPU time used in microseconds */
1536 /* Bytes 32-41 contain the date as EBCDIC MM/DD/YYYY */
1537 memcpy (buf+32, dattim+16, 10);
1538 /* Bytes 42-47 contain binary zeroes */
1539 /* Bytes 48-57 contain the date as EBCDIC YYYY-MM-DD */
1540 memcpy (buf+48, dattim+26, 10);
1541 /* Byte 58 contains the diagnose 270 version code */
1542 buf[58] = 0x01;
1543 /* Byte 59 contains the user's default date format */
1544 buf[59] = DIAG_DATEFMT_ISO;
1545 /* Byte 60 contains the system default date format */
1546 buf[60] = DIAG_DATEFMT_ISO;
1547 /* Bytes 61-63 contain binary zeroes */
1548
1549 #if 0
1550 logmsg ("Diagnose X\'%3.3X\':"
1551 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X "
1552 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t"
1553 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X "
1554 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t"
1555 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X "
1556 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t"
1557 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X "
1558 "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n",
1559 code, buf[0], buf[1], buf[2], buf[3],
1560 buf[4], buf[5], buf[6], buf[7],
1561 buf[8], buf[9], buf[10], buf[11],
1562 buf[12], buf[13], buf[14], buf[15],
1563 buf[16], buf[17], buf[18], buf[19],
1564 buf[20], buf[21], buf[22], buf[23],
1565 buf[24], buf[25], buf[26], buf[27],
1566 buf[28], buf[29], buf[30], buf[31],
1567 buf[32], buf[33], buf[34], buf[35],
1568 buf[36], buf[37], buf[38], buf[39],
1569 buf[40], buf[41], buf[42], buf[43],
1570 buf[44], buf[45], buf[46], buf[47],
1571 buf[48], buf[49], buf[50], buf[51],
1572 buf[52], buf[53], buf[54], buf[55],
1573 buf[56], buf[57], buf[58], buf[59],
1574 buf[60], buf[61], buf[63], buf[63]);
1575 #endif
1576
1577 /* Enforce maximum length to store */
1578 if (buflen > sizeof(buf))
1579 buflen = sizeof(buf);
1580
1581 /* Store the response buffer at the operand location */
1582 ARCH_DEP(vstorec) (buf, buflen-1, bufadr, USE_REAL_ADDR, regs);
1583
1584 } /* end function pseudo_timer */
1585
1586 /*-------------------------------------------------------------------*/
1587 /* Pending Page Release (Function code 0x214) */
1588 /*-------------------------------------------------------------------*/
ARCH_DEP(diag_ppagerel)1589 int ARCH_DEP(diag_ppagerel) (int r1, int r2, REGS *regs)
1590 {
1591 U32 abs, start, end; /* Absolute frame addresses */
1592 BYTE skey; /* Specified storage key */
1593 BYTE func; /* Function code... */
1594 #define DIAG214_EPR 0x00 /* Establish pending release */
1595 #define DIAG214_CPR 0x01 /* Cancel pending release */
1596 #define DIAG214_CAPR 0x02 /* Cancel all pending release*/
1597 #define DIAG214_CPRV 0x03 /* Cancel and validate */
1598
1599 /* Program check if R1 is not an even-numbered register */
1600 if (r1 & 1)
1601 {
1602 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1603 return 0;
1604 }
1605
1606 /* Extract the function code from R1+1 register bits 24-31 */
1607 func = regs->GR_L(r1+1) & 0xFF;
1608
1609 /* Extract the start/end addresses from R1 and R1+1 registers */
1610 start = regs->GR_L(r1) & STORAGE_KEY_PAGEMASK;
1611 end = regs->GR_L(r1+1) & STORAGE_KEY_PAGEMASK;
1612
1613 /* Validate start/end addresses if function is not CAPR */
1614 if (func != DIAG214_CAPR
1615 && (start > end || end > regs->mainlim))
1616 {
1617 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1618 return 0;
1619 }
1620
1621 /* Process depending on function code */
1622 switch (func)
1623 {
1624 case DIAG214_EPR: /* Establish Pending Release */
1625 break;
1626
1627 case DIAG214_CPR: /* Cancel Pending Release */
1628 case DIAG214_CPRV: /* Cancel Pending Release and Validate */
1629
1630 /* Do not set storage keys if R2 is register 0 */
1631 if (r2 == 0) break;
1632
1633 /* Obtain key from R2 register bits 24-28 */
1634 skey = regs->GR_L(r2) & (STORKEY_KEY | STORKEY_FETCH);
1635
1636 /* Set storage key for each frame within specified range */
1637 for (abs = start; abs <= end; abs += STORAGE_KEY_PAGESIZE)
1638 {
1639 STORAGE_KEY(abs, regs) &= ~(STORKEY_KEY | STORKEY_FETCH);
1640 STORAGE_KEY(abs, regs) |= skey;
1641 } /* end for(abs) */
1642
1643 break;
1644
1645 case DIAG214_CAPR: /* Cancel All Pending Releases */
1646 break;
1647
1648 default: /* Invalid function code */
1649 ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
1650 return 0;
1651 } /* end switch(func) */
1652
1653 /* Return condition code zero */
1654 return 0;
1655
1656 } /* end function diag_ppagerel */
1657
1658
1659 /*-------------------------------------------------------------------*/
1660 /* B2F0 IUCV - Inter User Communications Vehicle [S] */
1661 /*-------------------------------------------------------------------*/
DEF_INST(inter_user_communication_vehicle)1662 DEF_INST(inter_user_communication_vehicle)
1663 {
1664 int b2; /* Effective addr base */
1665 VADR effective_addr2; /* Effective address */
1666
1667 S(inst, regs, b2, effective_addr2);
1668 #if defined(FEATURE_ECPSVM)
1669 if(ecpsvm_doiucv(regs,b2,effective_addr2)==0)
1670 {
1671 return;
1672 }
1673 #endif
1674
1675
1676 /* Program check if in problem state,
1677 the IUCV instruction generates an operation exception
1678 rather then a priviliged operation exception when
1679 executed in problem state *JJ */
1680 if ( PROBSTATE(®s->psw) )
1681 ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION);
1682
1683 SIE_INTERCEPT(regs);
1684
1685 if( HDC3(debug_iucv, b2, effective_addr2, regs) )
1686 return;
1687
1688 PTT(PTT_CL_ERR,"*IUCV",b2,effective_addr2,regs->psw.IA_L);
1689
1690 /* Set condition code to indicate IUCV not available */
1691 regs->psw.cc = 3;
1692
1693 }
1694
1695 #endif /*FEATURE_EMULATE_VM*/
1696
1697
1698 #if !defined(_GEN_ARCH)
1699
1700 #if defined(_ARCHMODE2)
1701 #define _GEN_ARCH _ARCHMODE2
1702 #include "vm.c"
1703 #endif
1704
1705 #if defined(_ARCHMODE3)
1706 #undef _GEN_ARCH
1707 #define _GEN_ARCH _ARCHMODE3
1708 #include "vm.c"
1709 #endif
1710
1711 #endif /*!defined(_GEN_ARCH)*/
1712