Page 1 of 1

Solved! CPUID in C-Backend! Problems with returning values

Posted: Sat Aug 09, 2025 2:28 pm
by SMaag
The CPUID Function in PB, ASM and C-Backend.
It is working now.
But I have problems returning the register values in the C-Code.
I found a way. But I guess it should be possible in an easier way.
At the moment I use extra variables with Protected and
copy the values in C-Code first to this variables and from there
with PB Code the returning Pointer vars!

Does anyone know how to return varibales dirctly in the C-code
without the PokeL(*EAX, a) commands

here the CPUID example
see Procedure CPUID section C-Backend

Code: Select all

Procedure.i CPUID_IsSupported()
; ======================================================================
;  NAME: CPUID_IsSupported
;  DESC: Checks if CPUID is supported
;  DESC: on AMD/Intel x64 Processors CPUID is always supported
;  DESC: It was introduced in 1993 with the Pentium CPUs
;  DESC: But better to do a check bevor calling !CPUID functions
;  VAR(leaf.l): the numerical id of the requested level of information 
;  RET : #TRUE if supported
; ====================================================================== 

  CompilerIf (#PB_Compiler_Processor = #PB_Processor_x64)
    ProcedureReturn #True  ;  on x64 CPUs CPUID is always supported
     
  CompilerElseIf (#PB_Compiler_Processor = #PB_Processor_x86)      
    
    CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
      !PUSHFD
      !POP EAX
      !MOV EDX, EAX
      !XOR EAX, 0x00200000
      !PUSH EAX
      !POPFD
      !PUSHFD
      !POP EAX
      !XOR EAX, EDX
      !JNE IsCpuid_OK
      !XOR EAX, EAX   ; ProcedureReturn #False
      !RET
      !IsCpuid_OK:
      !MOV EAX, 1     ; ProcedureReturn #True
      !RET     
      
    CompilerElseIf #PB_Compiler_Backend = #PB_Backend_C 
      !asm volatile (".intel_syntax noprefix;"
      !"pushfd;"
      !"pop EAX;"
      !"mov EDX, EAX;"
      !"xor EAX, 0x00200000;"  
      !"push EAX;"
      !"popfd;"
      !"pushfd;"
      !"pop EAX;"
      !"xor EAX, EDX;"
      
      !"jne IsCpuid_OK;"
      !"mov %[retval], 0;"
      !"jmp IsCpuid_EXIT;"
      
      !"IsCpuid_OK:"
      !"mov %[retval], 1;"
      
      !"IsCpuid_EXIT:"
          
      !".att_syntax;"
      !: [retval] "=r" (r)
      !);
      
      !return r       ; ProcedureReturn r   
    CompilerEndIf
    
  CompilerElse
    
    ProcedureReturn #False
    
  CompilerEndIf
EndProcedure    

Procedure.i CPUID (Function.l, *EAX, *EBX, *ECX, *EDX)
; ======================================================================
;  NAME: CPUID
;  DESC: This wraps the CPUID instruction. And copies the return values
;  DESC: from CPUID to 4 Variables. CPID returns the values direct in
;  DESC: the x86 Registers EAX, EBX, ECX, EDX
;  VAR(function.l): the numerical ID of the requested level of information 
;  VAR(*EAX): Pointer to a 32Bit Long to receive EAX after !CPUID
;  VAR(*EBX): Pointer to a 32Bit Long to receive EBX after !CPUID
;  VAR(*ECX): Pointer to a 32Bit Long to receive ECX after !CPUID
;  VAR(*EDX): Pointer to a 32Bit Long to receive EDX after !CPUID
;  RET : TRUE if succseed
; ====================================================================== 
  
  DisableDebugger
  
  ; more informations for the CPUID instruction you can find here:
  ; https://c9x.me/x86/html/file_module_x86_id_45.html
  ; https://www.lowlevel.eu/wiki/CPUID
  If *EAX And *EBX And *ECX And *EDX
    If CPUID_IsSupported()
      
      CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
        CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)  
          !MOV EAX, DWORD [p.v_Function]
          !XOR ECX, ECX     ; Subleave = 0
          !CPUID
          !MOV EBP, DWORD [p.p_EAX]
          !MOV DWORD [EBP], EAX
          !MOV EBP, DWORD [p.p_EBX]
          !MOV DWORD [EBP], EBX
          !MOV EBP, DWORD [p.p_ECX]
          !MOV DWORD [EBP], ECX
          !MOV EBP, DWORD [p.p_EDX]
          !MOV DWORD [EBP], EDX        
        CompilerElse   
          !XOR RAX, RAX
          !MOV EAX, DWORD [p.v_Function]
          !XOR ECX, ECX     ; Subleave = 0
          !CPUID
          !MOV RBP, QWORD [p.p_EAX]
          !MOV DWORD [RBP], EAX
          !MOV RBP, QWORD [p.p_EBX]
          !MOV DWORD [RBP], EBX
          !MOV RBP, QWORD [p.p_ECX]
          !MOV DWORD [RBP], ECX
          !MOV RBP, QWORD [p.p_EDX]
          !MOV DWORD [RBP], EDX
        CompilerEndIf  
      
      CompilerElseIf #PB_Compiler_Backend = #PB_Backend_C
        Protected.l a, b, c, d
        !unsigned int reg_a, reg_b, reg_c, reg_d;
        
        !asm volatile ("cpuid;"  
        !: "=a" (reg_a), "=b" (reg_b), "=c" (reg_c), "=d" (reg_d)	
        !: "0" (v_function)
        !);
        ; ---------------------------------------
        ; thats my way how to return values 
        !v_a = reg_a;
        !v_b = reg_b;
        !v_c = reg_c;
        !v_d = reg_d;
        
        PokeL(*EAX, a)
        PokeL(*EBX, b)
        PokeL(*ECX, c)
        PokeL(*EDX, d)
        ; ---------------------------------------
      CompilerEndIf
      ProcedureReturn #True
      
    Else
      *EAX = 0 : *EBX = 0 : *ECX = 0 : *EDX = 0 
      ProcedureReturn #False
    EndIf
    
  Else 
    ProcedureReturn #False
  EndIf
  
  EnableDebugger
  
EndProcedure

Procedure.s GetCPUVendorID()
  ; ======================================================================
  ;  NAME: GetCPUVendorID
  ;  DESC: Reads the 12 Character long Vendor ID of the CPU 
  ;  RET.s: VendorID String {"AuthenticAMD", "GenuineIntel" ...}
  ; ====================================================================== 
    
    ; the VendorName contains 12 Chars in ASCII, token from the Registers EBX,EDX,ECX    
    Protected.l mEAX, mEBX, mECX, mEDX     
    
    If CPUID(0, @mEAX, @mEBX, @mECX, @mEDX)
      ProcedureReturn PeekS(@mEBX, 4, #PB_Ascii) + PeekS(@mEDX, 4, #PB_Ascii) + PeekS(@mECX, 4, #PB_Ascii)      
    Else
      ProcedureReturn "unknown Vendor"
    EndIf
  
  EndProcedure

Define.l mEAX, mEBX, mECX, mEDX

If CPUID(0, @mEAX, @mEBX, @mECX, @mEDX)
  Debug "CPU ID is supported"
  Debug "EAX = $" + Hex(mEAX)
  Debug "EBX = $" + Hex(mEBX)
  Debug "ECX = $" + Hex(mECX)
  Debug "EDX = $" + Hex(mEDX)
  Debug ""
  Debug "Vendor ID = " + GetCPUVendorID()
Else
  Debug " CPU ID not supported"  
EndIf
  

Re: CPUID in C-Backend! Problems with returning values

Posted: Sat Aug 09, 2025 2:58 pm
by mk-soft

Code: Select all

Procedure.i CPUID (Function.l, *EAX.INTEGER, *EBX.INTEGER, *ECX.INTEGER, *EDX.INTEGER)
...
*EAX\i = a
*EBX\i = b
*ECX\i = c
*EDX\i = d
...

Re: CPUID in C-Backend! Problems with returning values

Posted: Sat Aug 09, 2025 3:05 pm
by SMaag
thank's for the answer. But I have to explain more detailed.
The way with .Integer I know.
I'd like to know how is the direct way in C-Code

Code: Select all

Procedure.i CPUID (Function.l, *EAX, *EBX, *ECX, *EDX)
       !unsigned int reg_a, reg_b, reg_c, reg_d;
        
        !asm volatile ("cpuid;"  
        !: "=a" (reg_a), "=b" (reg_b), "=c" (reg_c), "=d" (reg_d)	
        !: "0" (v_function)
        !);
	; how to direct return reg_a, reg_b ... ???
	!p.p_EAX = reg_a;  how???
...

Re: CPUID in C-Backend! Problems with returning values

Posted: Sat Aug 09, 2025 3:34 pm
by SMaag
that's the way I searched for!
I found it in the C-Output

Code: Select all

        Protected reg_a, reg_b, reg_c, reg_d        
        ; !unsigned int reg_a, reg_b, reg_c, reg_d;       
        
        !asm volatile ("cpuid;"  
        !: "=a" (v_reg_a), "=b" (v_reg_b), "=c" (v_reg_c), "=d" (v_reg_d)	
        !: "0" (v_function)
        !);
        !p_eax->f_i=v_reg_a;
        !p_ebx->f_i=v_reg_b;
        !p_ecx->f_i=v_reg_c;
        !p_edx->f_i=v_reg_d;
but this is better to understand

Code: Select all

       Protected reg_a, reg_b, reg_c, reg_d        
        ; !unsigned int reg_a, reg_b, reg_c, reg_d;       
        
        !asm volatile ("cpuid;"  
        !: "=a" (v_reg_a), "=b" (v_reg_b), "=c" (v_reg_c), "=d" (v_reg_d)	
        !: "0" (v_function)
        !);
        
        *EAX\i = reg_a
        *EBX\i = reg_b
        *ECX\i = reg_c
        *EDX\i = reg_d


Re: Solved! CPUID in C-Backend! Problems with returning values

Posted: Sun Aug 10, 2025 2:49 am
by idle
also module here
viewtopic.php?t=61060

Re: Solved! CPUID in C-Backend! Problems with returning values

Posted: Sun Aug 10, 2025 6:39 pm
by SMaag
also module here
viewtopic.php?t=61060
thank's @idle
How stupid! seems like I've reinvented the wheel! Well, just for practice!

Re: Solved! CPUID in C-Backend! Problems with returning values

Posted: Mon Aug 11, 2025 7:56 am
by idle
SMaag wrote: Sun Aug 10, 2025 6:39 pm
also module here
viewtopic.php?t=61060
thank's @idle
How stupid! seems like I've reinvented the wheel! Well, just for practice!
think we're all guilty of doing that sometimes :lol: