@@ -151,7 +151,7 @@ typedef enum powerpc_iname {
151151 iBLTm , iBC , iBCL , iB , iBL , iBLR , iBCTR , iBCTRL , iRLWINM , iNOP , iORI ,
152152 iXORIS , iLDX , iLWZX , iSLW , iAND , iSUB , iLBZX , iNEG , iNOT , iSTWX , iSTBX ,
153153 iMULLW , iADD , iLHZX , iXOR , iMFLR , iSTHX , iMR , iOR , iDIVWU , iMTLR ,
154- iMTCTR , iDIVW , iLFSX , iSRW , iSTFSX , iSRAW , iEXTSH , iEXTSB , iLWZ , iLBZ ,
154+ iMTCTR , iDIVW , iLFSX , iSRW , iSTFSX , iSRAW , iEXTSH , iEXTSB , iEXTSW , iLWZ , iLBZ ,
155155 iSTW , iSTWU , iSTB , iLHZ , iSTH , iLFS , iLFD , iSTFS , iSTFD , iLD , iFDIVS ,
156156 iFSUBS , iFADDS , iFMULS , iSTD , iSTDU , iFRSP , iFCTIWZ , iFSUB , iFNEG ,
157157} powerpc_iname_t ;
@@ -1100,6 +1100,7 @@ static const struct powerpc_opcode powerpc_opcodes[] = {
11001100{ "sraw" , XRC (31 ,792 ,0 ), X_MASK , PPCCOM , { RA , RS , RB } },
11011101{ "extsh" , XRC (31 ,922 ,0 ), XRB_MASK , PPCCOM , { RA , RS } },
11021102{ "extsb" , XRC (31 ,954 ,0 ), XRB_MASK , PPC , { RA , RS } },
1103+ { "extsw" , XRC (31 ,986 ,0 ), XRB_MASK , PPC64 , { RA , RS } },
11031104
11041105{ "lwz" , OP (32 ), OP_MASK , PPCCOM , { RT , D , RA0 } },
11051106{ "lbz" , OP (34 ), OP_MASK , COM , { RT , D , RA0 } },
@@ -1221,11 +1222,38 @@ PPC_Malloc( size_t size )
12211222# define SA ( a , b ) (b)
12221223#endif
12231224
1225+ /* Select Endian - first for big endian, second for little endian */
1226+ #ifdef __BIG_ENDIAN__
1227+ # define SE ( a , b ) (a)
1228+ #else
1229+ # define SE ( a , b ) (b)
1230+ #endif
1231+
1232+ /* indices for accessing high/low 16-bit halves of a 32-bit int via
1233+ * a union of short[2]; on big-endian [0] is high, on little-endian [1] is */
1234+ #define HI16 SE( 0, 1 )
1235+ #define LO16 SE( 1, 0 )
1236+
1237+ /* offset of high/low 32-bit word within a 64-bit double stored in memory */
1238+ #define FPRHI SE( 0, 4 )
1239+ #define FPRLO SE( 4, 0 )
1240+
12241241#define ELF32 SL( SA( 1, 0 ), 0 )
12251242#define ELF64 SL( 0, SA( 1, 0 ) )
12261243#define OSX32 SL( SA( 0, 1 ), 0 )
12271244#define OSX64 SL( 0, SA( 0, 1 ) )
12281245
1246+ /* Distinguish ELFv1 (ppc64be) from ELFv2 (ppc64le) ABI.
1247+ * ELFv1 uses Official Procedure Descriptors (OPD) for function pointers;
1248+ * ELFv2 uses direct code addresses. */
1249+ #if ELF64 && defined(_CALL_ELF ) && _CALL_ELF == 2
1250+ # define ELFV2 1
1251+ # define ELFV1 0
1252+ #else
1253+ # define ELFV2 0
1254+ # define ELFV1 ELF64
1255+ #endif
1256+
12291257/* native length load/store instructions ( L stands for long ) */
12301258#define iSTLU SL( iSTWU, iSTDU )
12311259#define iSTL SL( iSTW, iSTD )
@@ -1248,11 +1276,11 @@ PPC_Malloc( size_t size )
12481276 * prepared properly */
12491277#define STACK_RTEMP (-16)
12501278
1251- #if ELF64
1279+ #if ELFV1
12521280/*
1253- * Official Procedure Descriptor
1281+ * Official Procedure Descriptor (ELFv1 only)
12541282 * we need to prepare one for generated code if we want to call it
1255- * as function
1283+ * as function. ELFv2 (ppc64le) uses direct code addresses instead.
12561284 */
12571285typedef struct {
12581286 void * function ;
@@ -1411,8 +1439,8 @@ typedef struct VM_Data {
14111439 // fixed number used to convert from integer to float
14121440 unsigned int floatBase ; // 0x59800004
14131441
1414- #if ELF64
1415- // official procedure descriptor
1442+ #if ELFV1
1443+ // official procedure descriptor (ELFv1 only)
14161444 opd_t opd ;
14171445#endif
14181446
@@ -1873,9 +1901,9 @@ PPC_EmitConst( source_instruction_t * const i_const )
18731901 in ( iLI , rFIRST , 0 );
18741902 in ( iORI , rFIRST , rFIRST , i_const -> arg .i );
18751903 } else {
1876- in ( iLIS , rFIRST , i_const -> arg .ss [ 0 ] );
1877- if ( i_const -> arg .us [ 1 ] != 0 )
1878- in ( iORI , rFIRST , rFIRST , i_const -> arg .us [ 1 ] );
1904+ in ( iLIS , rFIRST , i_const -> arg .ss [ HI16 ] );
1905+ if ( i_const -> arg .us [ LO16 ] != 0 )
1906+ in ( iORI , rFIRST , rFIRST , i_const -> arg .us [ LO16 ] );
18791907 }
18801908
18811909 } else {
@@ -2177,9 +2205,9 @@ VM_CompileFunction( source_instruction_t * const i_first )
21772205 in ( iLI , r3 , 0 );
21782206 in ( iORI , r3 , r3 , i_const -> arg .i );
21792207 } else {
2180- in ( iLIS , r3 , i_const -> arg .ss [ 0 ] );
2181- if ( i_const -> arg .us [ 1 ] != 0 )
2182- in ( iORI , r3 , r3 , i_const -> arg .us [ 1 ] );
2208+ in ( iLIS , r3 , i_const -> arg .ss [ HI16 ] );
2209+ if ( i_const -> arg .us [ LO16 ] != 0 )
2210+ in ( iORI , r3 , r3 , i_const -> arg .us [ LO16 ] );
21832211 }
21842212 gpr_pos -- ;
21852213 } else {
@@ -2240,6 +2268,9 @@ VM_CompileFunction( source_instruction_t * const i_first )
22402268 in ( iLI , r3 , i_const -> arg .si ); // negative value
22412269 in ( iMR , r4 , rPSTACK ); // push PSTACK on argument list
22422270
2271+ #if ELFV2
2272+ in ( iMR , r12 , r0 ); // ELFv2: r12 must hold target addr
2273+ #endif
22432274 in ( iMTCTR , r0 );
22442275 in ( iBCTRL );
22452276 }
@@ -2257,16 +2288,20 @@ VM_CompileFunction( source_instruction_t * const i_first )
22572288 in ( iRLWINM , rFIRST , rFIRST , GPRLEN_SHIFT , 0 , 31 - GPRLEN_SHIFT ); // mul * GPRLEN
22582289 in ( iLLX , r0 , rFIRST , r0 ); // load pointer
22592290
2260- in ( iB , +4 * (3 + (rFIRST != r3 ? 1 : 0 ) ) ); // XXX jump !
2291+ in ( iB , +4 * (4 + (rFIRST != r3 ? 1 : 0 ) ) ); // skip syscall-specific code to common tail
22612292
22622293 /* syscall */
22632294 in ( iLL , r0 , VM_Data_Offset ( AsmCall ), rVMDATA ); // get asmCall pointer
22642295 /* rFIRST can be r3 or some static register */
22652296 if ( rFIRST != r3 )
22662297 in ( iMR , r3 , rFIRST ); // push OPSTACK top value on argument list
2298+ in ( iEXTSW , r3 , r3 ); // sign-extend 32-bit syscall number for 64-bit ABI
22672299 in ( iMR , r4 , rPSTACK ); // push PSTACK on argument list
22682300
22692301 /* common code */
2302+ #if ELFV2
2303+ in ( iMR , r12 , r0 ); // ELFv2: r12 must hold target addr
2304+ #endif
22702305 in ( iMTCTR , r0 );
22712306 in ( iBCTRL );
22722307
@@ -2304,8 +2339,8 @@ VM_CompileFunction( source_instruction_t * const i_first )
23042339 MAYBE_EMIT_CONST ();
23052340 {
23062341 signed long int hi , lo ;
2307- hi = i_now -> arg .ss [ 0 ];
2308- lo = i_now -> arg .ss [ 1 ];
2342+ hi = i_now -> arg .ss [ HI16 ];
2343+ lo = i_now -> arg .ss [ LO16 ];
23092344 if ( lo < 0 )
23102345 hi += 1 ;
23112346
@@ -2622,15 +2657,18 @@ VM_CompileFunction( source_instruction_t * const i_first )
26222657 in ( iLI , r5 , 0 );
26232658 r5_ori = i_now -> arg .i ;
26242659 } else {
2625- in ( iLIS , r5 , i_now -> arg .ss [ 0 ] );
2626- r5_ori = i_now -> arg .us [ 1 ];
2660+ in ( iLIS , r5 , i_now -> arg .ss [ HI16 ] );
2661+ r5_ori = i_now -> arg .us [ LO16 ];
26272662 }
26282663
26292664 in ( iLL , r0 , VM_Data_Offset ( BlockCopy ), rVMDATA ); // get blockCopy pointer
26302665
26312666 if ( r5_ori )
26322667 in ( iORI , r5 , r5 , r5_ori );
26332668
2669+ #if ELFV2
2670+ in ( iMR , r12 , r0 ); // ELFv2: r12 must hold target addr
2671+ #endif
26342672 in ( iMTCTR , r0 );
26352673
26362674 if ( rFIRST != r4 )
@@ -2664,8 +2702,8 @@ VM_CompileFunction( source_instruction_t * const i_first )
26642702 EMIT_FALSE_CONST ();
26652703
26662704 signed short int hi , lo ;
2667- hi = i_const -> arg .ss [ 0 ];
2668- lo = i_const -> arg .ss [ 1 ];
2705+ hi = i_const -> arg .ss [ HI16 ];
2706+ lo = i_const -> arg .ss [ LO16 ];
26692707 if ( lo < 0 )
26702708 hi += 1 ;
26712709
@@ -2800,8 +2838,8 @@ VM_CompileFunction( source_instruction_t * const i_first )
28002838 fpr_pos ++ ;
28012839 in ( iXORIS , rFIRST , rFIRST , 0x8000 );
28022840 in ( iLIS , r0 , 0x4330 );
2803- in ( iSTW , rFIRST , stack_temp + 4 , r1 );
2804- in ( iSTW , r0 , stack_temp , r1 );
2841+ in ( iSTW , rFIRST , stack_temp + FPRLO , r1 );
2842+ in ( iSTW , r0 , stack_temp + FPRHI , r1 );
28052843 in ( iLFS , fTMP , VM_Data_Offset ( floatBase ), rVMDATA );
28062844 in ( iLFD , fFIRST , stack_temp , r1 );
28072845 in ( iFSUB , fFIRST , fFIRST , fTMP );
@@ -2814,7 +2852,7 @@ VM_CompileFunction( source_instruction_t * const i_first )
28142852 gpr_pos ++ ;
28152853 in ( iFCTIWZ , fFIRST , fFIRST );
28162854 in ( iSTFD , fFIRST , stack_temp , r1 );
2817- in ( iLWZ , rFIRST , stack_temp + 4 , r1 );
2855+ in ( iLWZ , rFIRST , stack_temp + FPRLO , r1 );
28182856 fpr_pos -- ;
28192857 break ;
28202858 }
@@ -2994,8 +3032,8 @@ PPC_ComputeCode( vm_t *vm )
29943032
29953033 vm_data_t * data = (vm_data_t * )dataAndCode ;
29963034
2997- #if ELF64
2998- // prepare Official Procedure Descriptor for the generated code
3035+ #if ELFV1
3036+ // ELFv1: prepare Official Procedure Descriptor for the generated code
29993037 // and retrieve real function pointer for helper functions
30003038
30013039 opd_t * ac = (void * )VM_AsmCall , * bc = (void * )VM_BlockCopy ;
@@ -3084,12 +3122,8 @@ VM_Compile( vm_t *vm, vmHeader_t *header )
30843122 i_first = PPC_Malloc ( sizeof ( source_instruction_t ) );
30853123 i_first -> next = NULL ;
30863124
3087- // realloc instructionPointers with correct size
3088- // use Z_Malloc so vm.c will be able to free the memory
3089- if ( sizeof ( void * ) != sizeof ( int ) ) {
3090- Z_Free ( vm -> instructionPointers );
3091- vm -> instructionPointers = Z_Malloc ( header -> instructionCount * sizeof ( void * ) );
3092- }
3125+ // vm->instructionPointers is already allocated as intptr_t* by vm.c
3126+ // (pointer-sized entries), so no reallocation needed
30933127 di_pointers = (void * )vm -> instructionPointers ;
30943128 memset ( di_pointers , 0 , header -> instructionCount * sizeof ( void * ) );
30953129
@@ -3123,12 +3157,10 @@ VM_Compile( vm_t *vm, vmHeader_t *header )
31233157 i_now -> next = NULL ;
31243158
31253159 if ( vm_opInfo [op ] & opImm4 ) {
3126- union {
3127- unsigned char b [4 ];
3128- unsigned int i ;
3129- } c = { { code [ pc + 3 ], code [ pc + 2 ], code [ pc + 1 ], code [ pc + 0 ] }, };
3130-
3131- i_now -> arg .i = c .i ;
3160+ i_now -> arg .i = (unsigned char )code [ pc ]
3161+ | ( (unsigned char )code [ pc + 1 ] << 8 )
3162+ | ( (unsigned char )code [ pc + 2 ] << 16 )
3163+ | ( (unsigned char )code [ pc + 3 ] << 24 );
31323164 pc += 4 ;
31333165 } else if ( vm_opInfo [op ] & opImm1 ) {
31343166 i_now -> arg .b = code [ pc ++ ];
@@ -3152,6 +3184,10 @@ VM_Compile( vm_t *vm, vmHeader_t *header )
31523184 Com_Printf ( S_COLOR_RED "Pointer %ld not initialized !\n" , i );
31533185#endif
31543186
3187+ /* flush data cache and invalidate instruction cache for generated code;
3188+ * PowerPC has split D/I caches and requires explicit synchronization */
3189+ __builtin___clear_cache ( vm -> codeBase , vm -> codeBase + vm -> codeLength );
3190+
31553191 /* mark memory as executable and not writeable */
31563192 if ( mprotect ( vm -> codeBase , vm -> codeLength , PROT_READ |PROT_EXEC ) ) {
31573193
@@ -3209,7 +3245,7 @@ VM_CallCompiled( vm_t *vm, int *args )
32093245 /* call generated code */
32103246 {
32113247 int ( * entry )( void * , int , void * );
3212- #ifdef __PPC64__
3248+ #if ELFV1
32133249 entry = (void * )& (vm_dataAndCode -> opd );
32143250#else
32153251 entry = (void * )(vm -> codeBase + vm_dataAndCode -> dataLength );
0 commit comments