1 /* XSTORE.C     (c) Copyright Jan Jaeger, 1999-2009                  */
2 /*              Expanded storage related instructions                */
3 
4 /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009      */
5 /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009      */
6 
7 /* MVPG moved from cpu.c to xstore.c   05/07/00 Jan Jaeger */
8 
9 /*-------------------------------------------------------------------*/
10 /* This module implements the expanded storage instructions          */
11 /* for the Hercules ESA/390 emulator.                                */
12 /*-------------------------------------------------------------------*/
13 
14 #include "hstdinc.h"
15 
16 #if !defined(_HENGINE_DLL_)
17 #define _HENGINE_DLL_
18 #endif
19 
20 #if !defined(_XSTORE_C_)
21 #define _XSTORE_C_
22 #endif
23 
24 #include "hercules.h"
25 #include "opcode.h"
26 #include "inline.h"
27 
28 #if defined(FEATURE_EXPANDED_STORAGE)
29 /*-------------------------------------------------------------------*/
30 /* B22E PGIN  - Page in from expanded storage                  [RRE] */
31 /*-------------------------------------------------------------------*/
DEF_INST(page_in)32 DEF_INST(page_in)
33 {
34 int     r1, r2;                         /* Values of R fields        */
35 VADR    vaddr;                          /* Virtual storage address   */
36 BYTE   *maddr;                          /* Main storage address      */
37 U32     xaddr;                          /* Expanded storage block#   */
38 size_t  xoffs;                          /* Byte offset into xpndstor */
39 
40     RRE(inst, regs, r1, r2);
41 
42     PRIV_CHECK(regs);
43 
44     if(SIE_STATB(regs, IC3, PGX))
45         longjmp(regs->progjmp, SIE_INTERCEPT_INST);
46 
47 #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
48     /* Cannot perform xstore page movement in XC mode */
49     if(SIE_STATB(regs, MX, XC))
50         longjmp(regs->progjmp, SIE_INTERCEPT_INST);
51 #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
52 
53     /* expanded storage block number */
54     xaddr = regs->GR_L(r2);
55 
56     if(SIE_MODE(regs))
57     {
58         xaddr += regs->sie_xso;
59         if(xaddr >= regs->sie_xsl)
60         {
61             PTT(PTT_CL_ERR,"*PGIN",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
62             regs->psw.cc = 3;
63             return;
64         }
65     }
66 
67     /* If the expanded storage block is not configured then
68        terminate with cc3 */
69     if (xaddr >= sysblk.xpndsize)
70     {
71         PTT(PTT_CL_ERR,"*PGIN",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
72         regs->psw.cc = 3;
73         return;
74     }
75 
76     /* Byte offset in expanded storage */
77     xoffs = (size_t)xaddr << XSTORE_PAGESHIFT;
78 
79     /* Obtain abs address, verify access and set ref/change bits */
80     vaddr = (regs->GR(r1) & ADDRESS_MAXWRAP(regs)) & XSTORE_PAGEMASK;
81     maddr = MADDRL (vaddr, 4096, USE_REAL_ADDR, regs, ACCTYPE_WRITE, 0);
82 
83     /* Copy data from expanded to main */
84     memcpy (maddr, sysblk.xpndstor + xoffs, XSTORE_PAGESIZE);
85 
86     /* cc0 means pgin ok */
87     regs->psw.cc = 0;
88 
89 } /* end DEF_INST(page_in) */
90 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
91 
92 
93 #if defined(FEATURE_EXPANDED_STORAGE)
94 /*-------------------------------------------------------------------*/
95 /* B22F PGOUT - Page out to expanded storage                   [RRE] */
96 /*-------------------------------------------------------------------*/
DEF_INST(page_out)97 DEF_INST(page_out)
98 {
99 int     r1, r2;                         /* Values of R fields        */
100 VADR    vaddr;                          /* Virtual storage address   */
101 BYTE   *maddr;                          /* Main storage address      */
102 U32     xaddr;                          /* Expanded storage block#   */
103 size_t  xoffs;                          /* Byte offset into xpndstor */
104 
105     RRE(inst, regs, r1, r2);
106 
107     PRIV_CHECK(regs);
108 
109     if(SIE_STATB(regs, IC3, PGX))
110         longjmp(regs->progjmp, SIE_INTERCEPT_INST);
111 
112 #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
113     /* Cannot perform xstore page movement in XC mode */
114     if(SIE_STATB(regs, MX, XC))
115         longjmp(regs->progjmp, SIE_INTERCEPT_INST);
116 #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
117 
118     /* expanded storage block number */
119     xaddr = regs->GR_L(r2);
120 
121     if(SIE_MODE(regs))
122     {
123         xaddr += regs->sie_xso;
124         if(xaddr >= regs->sie_xsl)
125         {
126             PTT(PTT_CL_ERR,"*PGOUT",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
127             regs->psw.cc = 3;
128             return;
129         }
130     }
131 
132     /* If the expanded storage block is not configured then
133        terminate with cc3 */
134     if (xaddr >= sysblk.xpndsize)
135     {
136         PTT(PTT_CL_ERR,"*PGOUT",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
137         regs->psw.cc = 3;
138         return;
139     }
140 
141     /* Byte offset in expanded storage */
142     xoffs = (size_t)xaddr << XSTORE_PAGESHIFT;
143 
144     /* Obtain abs address, verify access and set ref/change bits */
145     vaddr = (regs->GR(r1) & ADDRESS_MAXWRAP(regs)) & XSTORE_PAGEMASK;
146     maddr = MADDR (vaddr, USE_REAL_ADDR, regs, ACCTYPE_READ, 0);
147 
148     /* Copy data from main to expanded */
149     memcpy (sysblk.xpndstor + xoffs, maddr, XSTORE_PAGESIZE);
150 
151     /* cc0 means pgout ok */
152     regs->psw.cc = 0;
153 
154 } /* end DEF_INST(page_out) */
155 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
156 
157 
158 #if defined(FEATURE_MOVE_PAGE_FACILITY_2) && defined(FEATURE_EXPANDED_STORAGE)
159 /*-------------------------------------------------------------------*/
160 /* B259 IESBE - Invalidate Expanded Storage Block Entry        [RRE] */
161 /*-------------------------------------------------------------------*/
DEF_INST(invalidate_expanded_storage_block_entry)162 DEF_INST(invalidate_expanded_storage_block_entry)
163 {
164 int     r1, r2;                         /* Values of R fields        */
165 
166     RRE(inst, regs, r1, r2);
167 
168     PRIV_CHECK(regs);
169 
170 #if defined(_FEATURE_SIE)
171     if(SIE_STATNB(regs, EC0, MVPG))
172         longjmp(regs->progjmp, SIE_INTERCEPT_INST);
173 #endif /*defined(_FEATURE_SIE)*/
174 
175     /* Perform serialization before operation */
176     PERFORM_SERIALIZATION (regs);
177     OBTAIN_INTLOCK(regs);
178     SYNCHRONIZE_CPUS(regs);
179 
180     /* Invalidate page table entry */
181     ARCH_DEP(invalidate_pte) (inst[1], regs->GR_G(r1), regs->GR_L(r2), regs);
182 
183     RELEASE_INTLOCK(regs);
184 
185     /* Perform serialization after operation */
186     PERFORM_SERIALIZATION (regs);
187 
188 } /* end DEF_INST(invalidate_expanded_storage_block_entry) */
189 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
190 
191 
192 #if defined(_MSVC_)
193   /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */
194   #pragma optimize("",off)
195 #endif /*defined(_MSVC_)*/
196 
197 #if defined(FEATURE_MOVE_PAGE_FACILITY_2)
198 /*-------------------------------------------------------------------*/
199 /* B254 MVPG  - Move Page                                      [RRE] */
200 /*-------------------------------------------------------------------*/
DEF_INST(move_page)201 DEF_INST(move_page)
202 {
203 int     r1, r2;                         /* Register values           */
204 int     rc = 0;                         /* Return code               */
205 int     cc = 0;                         /* Condition code            */
206 VADR    vaddr1, vaddr2;                 /* Virtual addresses         */
207 RADR    raddr1=0, raddr2=0, xpkeya;     /* Real addresses            */
208 BYTE   *main1 = NULL, *main2 = NULL;    /* Mainstor addresses        */
209 BYTE   *sk1;                            /* Storage key address       */
210 BYTE    akey;                           /* Access key in register 0  */
211 BYTE    akey1, akey2;                   /* Access keys for operands  */
212 #if defined(FEATURE_EXPANDED_STORAGE)
213 int     xpvalid1 = 0, xpvalid2 = 0;     /* 1=Operand in expanded stg */
214 CREG    pte1 = 0, pte2 = 0;             /* Page table entry          */
215 U32     xpblk1 = 0, xpblk2 = 0;         /* Expanded storage block#   */
216 BYTE    xpkey1 = 0, xpkey2 = 0;         /* Expanded storage keys     */
217 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
218 
219     RRE(inst, regs, r1, r2);
220 
221 #if defined(_FEATURE_SIE)
222     if(SIE_STATNB(regs, EC0, MVPG))
223         longjmp(regs->progjmp, SIE_INTERCEPT_INST);
224 #endif /*defined(_FEATURE_SIE)*/
225 
226     /* Use PSW key as access key for both operands */
227     akey1 = akey2 = regs->psw.pkey;
228 
229     /* If register 0 bit 20 or 21 is one, get access key from R0 */
230     if (regs->GR_L(0) & 0x00000C00)
231     {
232         /* Extract the access key from register 0 bits 24-27 */
233         akey = regs->GR_L(0) & 0x000000F0;
234 
235         /* Priviliged operation exception if in problem state, and
236            the specified key is not permitted by the PSW key mask */
237         if ( PROBSTATE(&regs->psw)
238             && ((regs->CR(3) << (akey >> 4)) & 0x80000000) == 0 )
239             regs->program_interrupt (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION);
240 
241         /* If register 0 bit 20 is one, use R0 key for operand 1 */
242         if (regs->GR_L(0) & 0x00000800)
243             akey1 = akey;
244 
245         /* If register 0 bit 21 is one, use R0 key for operand 2 */
246         if (regs->GR_L(0) & 0x00000400)
247             akey2 = akey;
248     }
249 
250     /* Specification exception if register 0 bits 16-19 are
251        not all zero, or if bits 20 and 21 are both ones */
252     if ((regs->GR_L(0) & 0x0000F000) != 0
253         || (regs->GR_L(0) & 0x00000C00) == 0x00000C00)
254         regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION);
255 
256     /* Determine the logical addresses of each operand */
257     vaddr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs);
258     vaddr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs);
259 
260     /* Isolate the page addresses of each operand */
261     vaddr1 &= XSTORE_PAGEMASK;
262     vaddr2 &= XSTORE_PAGEMASK;
263 
264     /* Obtain the real or expanded address of each operand */
265     if ( !REAL_MODE(&regs->psw) || SIE_MODE(regs) )
266     {
267         /* Translate the second operand address to a real address */
268         if(!REAL_MODE(&regs->psw))
269         {
270             rc = ARCH_DEP(translate_addr) (vaddr2, r2, regs, ACCTYPE_READ);
271             raddr2 = regs->dat.raddr;
272         }
273         else
274             raddr2 = vaddr2;
275 
276         if(rc != 0 && rc != 2)
277             goto mvpg_progck;
278 
279         raddr2 = APPLY_PREFIXING (raddr2, regs->PX);
280 
281         if (raddr2 > regs->mainlim)
282             regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION);
283 
284 #if defined(_FEATURE_SIE)
285         if(SIE_MODE(regs)  && !regs->sie_pref)
286         {
287 
288 #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
289             if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr2,
290                 (SIE_STATB(regs, MX, XC) && AR_BIT(&regs->psw) && r2 > 0)
291                 ? r2 : USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE))
292 #else /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
293             if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr2,
294                     USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE))
295 #endif /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
296                 (regs->hostregs->program_interrupt) (regs->hostregs, regs->hostregs->dat.xcode);
297 
298             /* Convert host real address to host absolute address */
299             raddr2 = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX);
300         }
301 #endif /*defined(_FEATURE_SIE)*/
302 
303 #if defined(FEATURE_EXPANDED_STORAGE)
304         if(rc == 2)
305         {
306             FETCH_W(pte2,regs->mainstor + raddr2);
307             /* If page is invalid in real storage but valid in expanded
308                storage then xpblk2 now contains expanded storage block# */
309             if(pte2 & PAGETAB_ESVALID)
310             {
311                 xpblk2 = (pte2 & ZPGETAB_PFRA) >> 12;
312 #if defined(_FEATURE_SIE)
313                 if(SIE_MODE(regs))
314                 {
315                     /* Add expanded storage origin for this guest */
316                     xpblk2 += regs->sie_xso;
317                     /* If the block lies beyond this guests limit
318                        then we must terminate the instruction */
319                     if(xpblk2 >= regs->sie_xsl)
320                     {
321                         cc = 2;
322                         goto mvpg_progck;
323                     }
324                 }
325 #endif /*defined(_FEATURE_SIE)*/
326 
327                 rc = 0;
328                 xpvalid2 = 1;
329                 xpkeya = raddr2 +
330 #if defined(FEATURE_ESAME)
331                                    2048;
332 #else /*!defined(FEATURE_ESAME)*/
333                 /* For ESA/390 mode, the XPTE lies directly beyond
334                    the PTE, and each entry is 12 bytes long, we must
335                    therefor add 1024 + 8 times the page index */
336                                  1024 + ((vaddr2 & 0x000FF000) >> 9);
337 #endif /*!defined(FEATURE_ESAME)*/
338                 if (xpkeya > regs->mainlim)
339                     regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION);
340                 xpkey2 = regs->mainstor[xpkeya];
341 
342 /*DEBUG logmsg("MVPG pte2 = " F_CREG ", xkey2 = %2.2X, xpblk2 = %5.5X, akey2 = %2.2X\n",
343                   pte2,xpkey2,xpblk2,akey2);  */
344 
345             }
346             else
347             {
348                 cc = 2;
349                 goto mvpg_progck;
350             }
351         }
352 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
353 
354         /* Program check if second operand is not valid
355            in either main storage or expanded storage */
356         if (rc)
357         {
358             cc = 2;
359             goto mvpg_progck;
360         }
361 
362         /* Reset protection indication before calling translate_addr() */
363         regs->dat.protect = 0;
364         /* Translate the first operand address to a real address */
365         if(!REAL_MODE(&regs->psw))
366         {
367             rc = ARCH_DEP(translate_addr) (vaddr1, r1, regs, ACCTYPE_WRITE);
368             raddr1 = regs->dat.raddr;
369         }
370         else
371             raddr1 = vaddr1;
372 
373         if(rc != 0 && rc != 2)
374             goto mvpg_progck;
375 
376         raddr1 = APPLY_PREFIXING (raddr1, regs->PX);
377 
378         if (raddr1 > regs->mainlim)
379             regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION);
380 
381 #if defined(_FEATURE_SIE)
382         if(SIE_MODE(regs)  && !regs->sie_pref)
383         {
384 #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
385             if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr1,
386                 (SIE_STATB(regs, MX, XC) && AR_BIT(&regs->psw) && r1 > 0)
387                 ? r1 : USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE))
388 #else /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
389             if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr1,
390                     USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE))
391 #endif /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
392                 (regs->hostregs->program_interrupt) (regs->hostregs, regs->hostregs->dat.xcode);
393 
394             /* Convert host real address to host absolute address */
395             raddr1 = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX);
396         }
397 #endif /*defined(_FEATURE_SIE)*/
398 
399 #if defined(FEATURE_EXPANDED_STORAGE)
400         if(rc == 2)
401         {
402             FETCH_W(pte1,regs->mainstor + raddr1);
403             /* If page is invalid in real storage but valid in expanded
404                storage then xpblk1 now contains expanded storage block# */
405             if(pte1 & PAGETAB_ESVALID)
406             {
407                 xpblk1 = (pte1 & ZPGETAB_PFRA) >> 12;
408 #if defined(_FEATURE_SIE)
409                 if(SIE_MODE(regs))
410                 {
411                     /* Add expanded storage origin for this guest */
412                     xpblk1 += regs->sie_xso;
413                     /* If the block lies beyond this guests limit
414                        then we must terminate the instruction */
415                     if(xpblk1 >= regs->sie_xsl)
416                     {
417                         cc = 1;
418                         goto mvpg_progck;
419                     }
420                 }
421 #endif /*defined(_FEATURE_SIE)*/
422 
423                 rc = 0;
424                 xpvalid1 = 1;
425                 xpkeya = raddr1 +
426 #if defined(FEATURE_ESAME)
427                                   2048;
428 #else /*!defined(FEATURE_ESAME)*/
429                 /* For ESA/390 mode, the XPTE lies directly beyond
430                    the PTE, and each entry is 12 bytes long, we must
431                    therefor add 1024 + 8 times the page index */
432                               1024 + ((vaddr1 & 0x000FF000) >> 9);
433 #endif /*!defined(FEATURE_ESAME)*/
434                 if (xpkeya > regs->mainlim)
435                     regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION);
436                 xpkey1 = regs->mainstor[xpkeya];
437 
438 /*DEBUG  logmsg("MVPG pte1 = " F_CREG ", xkey1 = %2.2X, xpblk1 = %5.5X, akey1 = %2.2X\n",
439                   pte1,xpkey1,xpblk1,akey1);  */
440             }
441             else
442             {
443                 cc = 1;
444                 goto mvpg_progck;
445             }
446         }
447 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
448 
449         /* Program check if operand not valid in main or expanded */
450         if (rc)
451         {
452         cc = 1;
453             goto mvpg_progck;
454     }
455 
456         /* Program check if page protection or access-list controlled
457            protection applies to the first operand */
458         if (regs->dat.protect || (xpvalid1 && (pte1 & PAGETAB_PROT)))
459         {
460             regs->TEA = vaddr1 | TEA_PROT_AP | regs->dat.stid;
461             regs->excarid = (ACCESS_REGISTER_MODE(&regs->psw)) ? r1 : 0;
462             regs->program_interrupt (regs, PGM_PROTECTION_EXCEPTION);
463         }
464 
465     } /* end if(!REAL_MODE) */
466 
467 #if defined(FEATURE_EXPANDED_STORAGE)
468     /* Program check if both operands are in expanded storage, or
469        if first operand is in expanded storage and the destination
470        reference intention (register 0 bit 22) is set to one, or
471        if first operand is in expanded storage and pte lock bit on, or
472        if first operand is in expanded storage and frame invalid */
473     if ((xpvalid1 && xpvalid2)
474         || (xpvalid1 && (regs->GR_L(0) & 0x00000200))
475         || (xpvalid1 && (pte1 & PAGETAB_PGLOCK))
476         || (xpvalid1 && (xpblk1 >= sysblk.xpndsize)))
477     {
478         regs->dat.xcode = PGM_PAGE_TRANSLATION_EXCEPTION;
479         rc = 2;
480         cc = 1;
481         goto mvpg_progck;
482     }
483     /* More Program check checking, but at lower priority:
484        if second operand is in expanded storage and pte lock bit on, or
485        if second operand is in expanded storage and frame invalid */
486     if ((xpvalid2 && (pte2 & PAGETAB_PGLOCK))
487         || (xpvalid2 && (xpblk2 >= sysblk.xpndsize)))
488     {
489         /* re-do translation to set up TEA */
490         rc = ARCH_DEP(translate_addr) (vaddr2, r2, regs, ACCTYPE_READ);
491         regs->dat.xcode = PGM_PAGE_TRANSLATION_EXCEPTION;
492         cc = 1;
493         goto mvpg_progck;
494     }
495 
496     /* Perform protection checks */
497     if (xpvalid1)
498     {
499         /* Key check on expanded storage block if NoKey bit off in PTE */
500         if (akey1 != 0 && akey1 != (xpkey1 & STORKEY_KEY)
501             && (pte1 & PAGETAB_ESNK) == 0
502             && !((regs->CR(0) & CR0_STORE_OVRD) && ((xpkey1 & STORKEY_KEY) == 0x90)))
503         {
504             regs->program_interrupt (regs, PGM_PROTECTION_EXCEPTION);
505         }
506         sk1=NULL;
507     }
508     else
509 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
510     {
511         /* Obtain absolute address of main storage block,
512            check protection, and set reference and change bits */
513         main1 = MADDRL (vaddr1, 4096, r1, regs, ACCTYPE_WRITE_SKP, akey1);
514         sk1 = regs->dat.storkey;
515     }
516 
517 #if defined(FEATURE_EXPANDED_STORAGE)
518     if (xpvalid2)
519     {
520         /* Key check on expanded storage block if NoKey bit off in PTE */
521         if (akey2 != 0 && (xpkey2 & STORKEY_FETCH)
522             && akey2 != (xpkey2 & STORKEY_KEY)
523             && (pte2 & PAGETAB_ESNK) == 0)
524         {
525             regs->program_interrupt (regs, PGM_PROTECTION_EXCEPTION);
526         }
527     }
528     else
529 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
530     {
531         /* Obtain absolute address of main storage block,
532            check protection, and set reference bit.
533            Use last byte of page to avoid FPO area.  */
534         main2 = MADDR (vaddr2 | 0xFFF, r2, regs, ACCTYPE_READ, akey2);
535         main2 -= 0xFFF;
536     }
537 
538 #if defined(FEATURE_EXPANDED_STORAGE)
539     /* Perform page movement */
540     if (xpvalid2)
541     {
542         /* Set the main storage reference and change bits */
543         *sk1 |= (STORKEY_REF | STORKEY_CHANGE);
544 
545         /* Set Expanded Storage reference bit in the PTE */
546         STORE_W(regs->mainstor + raddr2, pte2 | PAGETAB_ESREF);
547 
548 
549         /* Move 4K bytes from expanded storage to main storage */
550         memcpy (main1,
551                 sysblk.xpndstor + ((size_t)xpblk2 << XSTORE_PAGESHIFT),
552                 XSTORE_PAGESIZE);
553     }
554     else if (xpvalid1)
555     {
556         /* Set Expanded Storage reference and change bits in the PTE */
557         STORE_W(regs->mainstor + raddr1, pte1 | PAGETAB_ESREF | PAGETAB_ESCHA);
558 
559         /* Move 4K bytes from main storage to expanded storage */
560         memcpy (sysblk.xpndstor + ((size_t)xpblk1 << XSTORE_PAGESHIFT),
561                 main2,
562                 XSTORE_PAGESIZE);
563     }
564     else
565 #endif /*defined(FEATURE_EXPANDED_STORAGE)*/
566     {
567         /* Set the main storage reference and change bits */
568         *sk1 |= (STORKEY_REF | STORKEY_CHANGE);
569 
570         /* Move 4K bytes from main storage to main storage */
571         memcpy (main1, main2, XSTORE_PAGESIZE);
572     }
573 
574     /* Return condition code zero */
575     regs->psw.cc = 0;
576     return;
577 
578 mvpg_progck:
579 
580     PTT(PTT_CL_ERR,"*MVPG",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
581 
582     /* If page translation exception (PTE invalid) and condition code
583         option in register 0 bit 23 is set, return condition code */
584     if ((regs->GR_L(0) & 0x00000100)
585         && regs->dat.xcode == PGM_PAGE_TRANSLATION_EXCEPTION
586         && rc == 2)
587     {
588         regs->psw.cc = cc;
589         return;
590     }
591 
592     /* Otherwise generate program check */
593     /* (Bit 29 of TEA is on for PIC 11 & operand ID also stored) */
594     if (regs->dat.xcode == PGM_PAGE_TRANSLATION_EXCEPTION)
595     {
596         regs->TEA |= TEA_MVPG;
597         regs->opndrid = (r1 << 4) | r2;
598     }
599     regs->program_interrupt (regs, regs->dat.xcode);
600 
601 } /* end DEF_INST(move_page) */
602 #endif /*defined(FEATURE_MOVE_PAGE_FACILITY_2)*/
603 
604 #if defined(_MSVC_)
605   /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */
606   #pragma optimize("",on)
607 #endif /*defined(_MSVC_)*/
608 
609 
610 #if !defined(_GEN_ARCH)
611 
612 #if defined(_ARCHMODE2)
613  #define  _GEN_ARCH _ARCHMODE2
614  #include "xstore.c"
615 #endif
616 
617 #if defined(_ARCHMODE3)
618  #undef   _GEN_ARCH
619  #define  _GEN_ARCH _ARCHMODE3
620  #include "xstore.c"
621 #endif
622 
623 #endif /*!defined(_GEN_ARCH)*/
624