Jump to content
Sign in to follow this  
Iran

C&C95's MMX detection doesn't work properly on my PC

Recommended Posts

The CPUID check function doesn't work, the game checks if my processor supports the CPUID instruction before trying to use it but that check fails at 0x004C660D, if that check is patched out it work correctly.

 

Another issue is that the game gets the processor family correctly according to Intel docs from 1996/1997, but to get the processor family for modern PCs you need to add an extra number to what the game already calculates:

 

The game calls CPUID with eax == 1, which puts the processor family, model and stepping info into EAX.

It then does some bit magic to place bits 8 to 11 into AL, then it saves that as processor family info.

 

For modern processors after taking bits 8 to 11 the game should also add the value of bits 20 to 27 according to Intel's latest documentation:

 

 

Output of the CPUID Instruction28 Application NoteEquation 5-1.Calculated Family ValueF = Extended Family + Family F = CPUID(1).EAX[27:20] + CPUID(1).EAX[11:8]The processor model is an 8-bit value obtained by shifting left 4 the Extended Model field of the processor signature returned by CPUID Function 1 then adding the Model field

 

The game stores the processor family info into a global BYTE so I'm not sure if it's able to hold family info for modern processors. It probably can hold it.

 

Here's the function that does the CPUID and MMX stuff:

.text:004C65F0 Check_CPUID     proc near               ; CODE XREF: _WinMain+25Bp
.text:004C65F0
.text:004C65F0 var_2           = byte ptr -2
.text:004C65F0 var_1           = byte ptr -1
.text:004C65F0
.text:004C65F0                 push    ebp
.text:004C65F1                 mov     ebp, esp
.text:004C65F3                 add     esp, 0FFFFFFFCh
.text:004C65F6                 mov     [ebp+var_1], 0
.text:004C65FA                 pushf
.text:004C65FB                 pop     eax
.text:004C65FC                 mov     ecx, eax
.text:004C65FE                 xor     eax, 40000h
.text:004C6603                 push    eax
.text:004C6604                 popf
.text:004C6605                 pushf
.text:004C6606                 pop     eax
.text:004C6607                 xor     eax, ecx
.text:004C6609                 mov     [ebp+var_2], 3
.text:004C660D                 jz      short Set_Processor ; This check fails in my PC
.text:004C660F                 push    ecx
.text:004C6610                 popf
.text:004C6611                 mov     [ebp+var_2], 4
.text:004C6615                 mov     eax, ecx
.text:004C6617                 xor     eax, 200000h
.text:004C661C                 push    eax
.text:004C661D                 popf
.text:004C661E                 pushf
.text:004C661F                 pop     eax
.text:004C6620                 xor     eax, ecx
.text:004C6622                 jz      short Set_Processor
.text:004C6624                 mov     [ebp+var_1], 1
.text:004C6628                 xor     eax, eax
.text:004C662A                 cpuid
.text:004C662C                 mov     dword_50B731, ebx ; Save processor ID string into 3 DWORDs
.text:004C6632                 mov     dword_50B735, edx
.text:004C6638                 mov     dword_50B739, ecx
.text:004C663E                 mov     dword_50B73D, 20h
.text:004C6648                 cmp     eax, 1
.text:004C664B                 jl      short Set_Processor
.text:004C664D                 xor     eax, eax
.text:004C664F                 inc     eax
.text:004C6650                 cpuid
.text:004C6652                 and     ax, 0F00h       ; eax contains model, family and processor type info
.text:004C6656                 shr     ax, 8           ; but for modern processors bits 20 to 27 also need to be added to eax to get modern processor family
.text:004C665A                 mov     [ebp+var_2], al
.text:004C665D
.text:004C665D Set_Processor:                          ; CODE XREF: Check_CPUID+1Dj
.text:004C665D                                         ; Check_CPUID+32j ...
.text:004C665D                 mov     al, [ebp+var_2]
.text:004C6660                 mov     Processor, al
.text:004C6665                 cmp     al, 5
.text:004C6667                 jl      short Ret
.text:004C6669                 mov     eax, 1
.text:004C666E                 cpuid
.text:004C6670                 test    edx, 800000h    ; MMX check, 23th bit of edx
.text:004C6676                 jz      short Ret
.text:004C6678                 mov     eax, 1          ; we have MMX so set eax to 1
.text:004C667D                 leave
.text:004C667E                 retn
.text:004C667F ; ---------------------------------------------------------------------------
.text:004C667F
.text:004C667F Ret:                                    ; CODE XREF: Check_CPUID+77j
.text:004C667F                                         ; Check_CPUID+86j
.text:004C667F                 xor     eax, eax
.text:004C6681                 leave
.text:004C6682                 retn
.text:004C6682 Check_CPUID     endp
.text:004C6682
Edited by Iran

Share this post


Link to post

Okay... not following entirely, though... I know this function, but, what exactly do I need to change in it?

Share this post


Link to post

Remove the checks at 0x004C65FA to 0x004C6622 and replace it with the CPUID detection code from http://wiki.osdev.org/CPUID, if that check fails jump to (0x004C665D) Set_Processor

Share this post


Link to post

Here's Doom 3's check:

 

 

/*
================
HasCPUID
================
*/
static bool HasCPUID() {
__asm 
{
pushfd // save eflags
pop eax
test eax, 0x00200000 // check ID bit
jz set21 // bit 21 is not set, so jump to set_21
and eax, 0xffdfffff // clear bit 21
push eax // save new value in register
popfd // store new value in flags
pushfd
pop eax
test eax, 0x00200000 // check ID bit
jz good
jmp err // cpuid not supported
set21:
or eax, 0x00200000 // set ID bit
push eax // store new value
popfd // store new value in EFLAGS
pushfd
pop eax
test eax, 0x00200000 // if bit 21 is on
jnz good
jmp err
}
 
err:
return false;
good:
return true;
}

Share this post


Link to post

C&C Renegade, Linux FDS:

 

 

.text:0830289E                 push    ebx
.text:0830289F                 pushf
.text:083028A0                 pop     eax
.text:083028A1                 mov     ebx, eax
.text:083028A3                 xor     eax, 200000h
.text:083028A8                 push    eax
.text:083028A9                 popf
.text:083028AA                 pushf
.text:083028AB                 pop     eax
.text:083028AC                 xor     eax, ebx
.text:083028AE                 setnz   al
.text:083028B1                 push    ebx
.text:083028B2                 popf
.text:083028B3                 pop     ebx
.text:083028B4                 and     eax, 0FFh
.text:083028B9                 push    edx
.text:083028BA                 mov     edx, eax
.text:083028BC                 mov     dword ptr hasCPUIDinstruction, edx
.text:083028C2                 pop     edx
.text:083028C3                 mov     hasCPUIDinstruction, 0
.text:083028CA                 retn

 

C&C Renegade, Windows FDS and game client:

 

 

.text:005ED209                 push    ebx
.text:005ED20A                 push    esi
.text:005ED20B                 push    edi
.text:005ED20C                 mov     dword ptr [ebp-4], 0
.text:005ED213                 mov     dword ptr [ebp-4], 0
.text:005ED21A                 push    ebx
.text:005ED21B                 pushf
.text:005ED21C                 pop     eax
.text:005ED21D                 mov     ebx, eax
.text:005ED21F                 xor     eax, 200000h
.text:005ED224                 push    eax
.text:005ED225                 popf
.text:005ED226                 pushf
.text:005ED227                 pop     eax
.text:005ED228                 xor     eax, ebx
.text:005ED22A                 jz      short loc_5ED233
.text:005ED22C                 mov     dword ptr [ebp-4], 1
.text:005ED233
.text:005ED233 loc_5ED233:                             ; CODE XREF: .text:005ED22Aj
.text:005ED233                 push    ebx
.text:005ED234                 popf
.text:005ED235                 pop     ebx
.text:005ED236                 mov     edx, [ebp-4]
.text:005ED239                 test    edx, edx
.text:005ED23B                 setnz   al
.text:005ED23E                 test    al, al
.text:005ED240                 mov     HasCPUIDInstruction?, al
Edited by Iran

Share this post


Link to post

Ah, cool, thanks. I'll ad it to the project asap

Share this post


Link to post

...not sure wtf to make of that :o

Share this post


Link to post

Ha totally have no clue what any of that really means.

Share this post


Link to post

The check is fails when I start the game with OllyDbg, instead of attaching after the game has been started. Noticed it while checking YR which has the same CPUID code.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×