11#include "driver.h"
22#include "runtime.h"
3+ #include "ppcinst.h"
34
45#define POINTER_SWAP32 (ptr ) (PULONG)(_Mmio_MungeAddressForBig(ptr, sizeof(ULONG)))
56
@@ -173,6 +174,61 @@ BOOL copyFromFb)
173174 return TRUE;
174175}
175176
177+ static inline LONG HookSignExtBranch (LONG x ) {
178+ return x & 0x2000000 ? (LONG )(x | 0xFC000000 ) : (LONG )(x );
179+ }
180+
181+ static inline LONG HookSignExt16 (SHORT x ) {
182+ return (LONG )x ;
183+ }
184+
185+ static BOOL IsRetAddrBad (PPPC_INSTRUCTION Addr ) {
186+ static ULONG s_RetAddrBad = 0 ;
187+ if (s_RetAddrBad != 0 ) return (ULONG )Addr == s_RetAddrBad ;
188+ PPPC_INSTRUCTION Insn = Addr ;
189+ // Two instructions afterwards is beq+ ?
190+ Insn += 2 ;
191+ if (Insn -> Primary_Op != BC_OP ) return FALSE;
192+ if (Insn -> Bform_BO != 0xD ) return FALSE;
193+ Insn ++ ;
194+ // Next bl (within next 5 instructions) leads to "lwz r3, x(r2)" insn (or a wrapper for that)
195+ PPPC_INSTRUCTION Bl = NULL ;
196+ for (int i = 0 ; i < 5 ; i ++ , Insn ++ ) {
197+ if (Insn -> Primary_Op != B_OP ) continue ;
198+ if (Insn -> Iform_LK == 0 ) continue ;
199+ Bl = Insn ;
200+ break ;
201+ }
202+
203+ if (Bl == NULL ) return FALSE;
204+
205+ Insn = (PPPC_INSTRUCTION )((ULONG )Bl + HookSignExtBranch (Bl -> Iform_LI << 2 ));
206+ if (Insn -> Primary_Op == LWZ_OP && Insn -> Dform_RA == 2 && Insn -> Dform_RT == 3 ) {
207+ // looks good...
208+ s_RetAddrBad = (ULONG )Addr ;
209+ return TRUE;
210+ }
211+
212+ // might be wrapping it, bl is within 16 instructions
213+ Bl = NULL ;
214+ for (int i = 0 ; i < 16 ; i ++ , Insn ++ ) {
215+ if (Insn -> Long == 0x4E800020 ) break ; // blr
216+ if (Insn -> Primary_Op != B_OP ) continue ;
217+ if (Insn -> Iform_LK == 0 ) continue ;
218+ Bl = Insn ;
219+ break ;
220+ }
221+ if (Bl == NULL ) return FALSE;
222+ Insn = (PPPC_INSTRUCTION )((ULONG )Bl + HookSignExtBranch (Bl -> Iform_LI << 2 ));
223+ if (Insn -> Primary_Op == LWZ_OP && Insn -> Dform_RA == 2 && Insn -> Dform_RT == 3 ) {
224+ // looks good...
225+ s_RetAddrBad = (ULONG )Addr ;
226+ return TRUE;
227+ }
228+
229+ return FALSE;
230+ }
231+
176232BOOL DrvCopyBits (
177233SURFOBJ * psoDest ,
178234SURFOBJ * psoSrc ,
@@ -199,7 +255,7 @@ POINTL *pptlSrc)
199255 to this function as a result of the following GDI functions:
200256 SetDIBits, SetDIBitsToDevice, GetDIBits, SetBitmapBits, and GetBitmapBits.
201257*/
202-
258+
203259 // If both surfaces are not device managed, just call original func:
204260 if (psoDest -> iType != STYPE_DEVBITMAP && psoSrc -> iType != STYPE_DEVBITMAP ) {
205261 return EngCopyBits (psoDest , psoSrc , pco , pxlo , prclDest , pptlSrc );
@@ -229,6 +285,15 @@ POINTL *pptlSrc)
229285 return CopyBitsSwap32 (psoDest , psoSrc , NULL , NULL , prclDest , & point , FALSE);
230286 }
231287
288+ // Try to detect CvtDFB2DIB, and fail if so.
289+ // On NT 3.5x, success in that scenario causes the caller to delete the source.
290+ // If that source is our device-managed surface, this CANNOT happen!
291+ if (psoSrc -> iType == STYPE_DEVBITMAP && psoDest -> iType == STYPE_BITMAP ) {
292+ // Get the return address of function
293+ PPPC_INSTRUCTION Insn = (PPPC_INSTRUCTION )__builtin_return_address (0 );
294+ if (IsRetAddrBad (Insn )) return FALSE;
295+ }
296+
232297 // Copying to framebuffer
233298 if (psoDest -> iType == STYPE_DEVBITMAP ) {
234299 // Source is always going to be a 32bpp bitmap
0 commit comments