We help IT Professionals succeed at work.

How to write following asm for Linux rhel4

Hi,
The following code works for Win32bit platfomr properly, how can i port the same code on Linux platfrom,
using c or c++ language only, can someone point out how to port the following code to linux platfrom.

#define INITIAL_APIC_ID_BITS 0xFF000000 // EBX[31:24] unique APIC ID    

int get_APICID()
{
     int nAPICPhysicalID = 0;
    unsigned    nIds;
    unsigned int reg_ebx = 0;
       __asm
       {
             mov   eax, 1
             cpuid
             mov  reg_ebx, ebx
       }
       nAPICPhysicalID = ((reg_ebx & INITIAL_APIC_ID_BITS) >> 24);

   return nAPICPhysicalID ;
}

Thanks in advance,
Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2009
Commented:
I assume that the architecture is the same (x86, to be able to use the cpuid instruction).

What compiler are you using ? I assume gcc ?


Try this :


#define INITIAL_APIC_ID_BITS 0xFF000000 /* EBX[31:24] unique APIC ID */
 
int get_APICID() {
    unsigned int reg_eax = 1;
    unsigned int reg_ebx = 0;
    __asm__ (
              "cpuid\n\t"
              : "=b" (reg_ebx)
              : "a" (reg_eax)
            );
    return ((reg_ebx & INITIAL_APIC_ID_BITS) >> 24);
}

Open in new window

Author

Commented:
Hi,
Thanks for your reply. I want to target both x86 and x64 bit platform.
will this work on x64 platform ? Like on Win64bit i have to use some __cpuid  C++ instrinsic so the same applies for Linux64bit also ?
CERTIFIED EXPERT
Top Expert 2009

Commented:
I've never tried it on an x86-64 platform, but it's also x86, so the instruction should be supported. Just give it a try ;)

Author

Commented:
Ok ,i will it a try and let you know.

Author

Commented:
Hi,

I tried the above solution, but it does not return any value, on Linux rhel4.tpp.com 2.6.9-5.EL i686 i686 i386 GNU/Linux machine.  where as i found a link, (http://fresh.t-systems-sfr.com/unix/privat/cpuid-20060917.src.tar.gz:a/cpuid-20060917/cpuid.c) and the same program return the desired output. But i am not able to undestand why the above program could not work, it does not return any value at all.

Could you please have a look at it, and suggest the require changes.
Thanks,
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> I tried the above solution, but it does not return any value

What do you mean by "not any value" ? On most systems, it will return 0. Is that what you get ?

>> and the same program return the desired output.

What is that desired output ?

Author

Commented:
Hi, Please have a look the below routine which i am trying to build to get the desired value, means different APIC ID's. I want to do the statatical sampling of APIC ID's.

When i tried to run the following routine, its give en error with gcc version 3.4.3 20041212 (Red Hat 3.4.3-9.EL4).
./neel: Exec format error. Wrong Architecture.

Please suggest.

#define INITIAL_APIC_ID_BITS 0xFF000000 /* EBX[31:24] unique APIC ID */
#include <stdio.h>

int get_APICID() {
    unsigned int reg_eax = 1;
    unsigned int reg_ebx = 0;
    __asm__ (
              "cpuid\n\t"
              : "=b" (reg_ebx)
              : "a" (reg_eax)
            );
    return ((reg_ebx & INITIAL_APIC_ID_BITS) >> 24);
}

int main()
{
  int n;
  for(int i=0; i<= 40; i++)
  {
       n = get_APICID();
       printf("value %d", n);
   }
}
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> ./neel: Exec format error. Wrong Architecture.

You have to compile on the same machine as you run it ... Did you do that ?
CERTIFIED EXPERT
Top Expert 2009

Commented:
Can you also answer my questions from the post with id 20742593 ?
Commented:
Under Linux it's likely the CPUID instruction is not available to user applications, or is emulated by the kernel and may not return the true info you're looking for.

Also the info you would get is generally not useful under Linux, as user programs can't do anything directly with the hardware.

What exactly are you trying to do?  Are you trying to reprogram the interrupt controller?  You can't do it this way at all under Linux.


There's probably a better and cleaner way.
Duncan RoeSoftware Developer
CERTIFIED EXPERT
Commented:
Depending on what you want to do, you might find the information in the text file /proc/cpuinfo to be useful. You can see how many processors there are, and their capabilities (flags)

Author

Commented:
Hi,

The following code is working for x86 i686 architecture. Now, when i tried to run on x64_64 arch. its not giving me the same output ? Could anyone suggest what need to be taken care while porting the following asm to x86_64 bit architecture ?

#define WORD_EAX  0
#define WORD_EBX  1
#define WORD_ECX  2
#define WORD_EDX  3

#define WORD_NUM  4
unsinged int reg=1;
unsigned int  words[WORD_NUM];

     __asm__("cpuid"
         : "=a" (words[WORD_EAX]),      /* output */
           "=b" (words[WORD_EBX]),
           "=c" (words[WORD_ECX]),
           "=d" (words[WORD_EDX])
         : "a" (reg));                  /* input */
return ((words[WORD_EBX] & INITIAL_APIC_ID_BITS) >> 24)

Thanks,
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> its not giving me the same output ?

Can you show both values ?

Can you also do a sizeof(unsigned int) on the x86_64 machine ?

Commented:
Please read this carefully:

You are barking up the wrong tree.  

On windows, it's quite possible to access the interrupt hardware.  Not trivial, as the system tries to protect that stuff, but possible.

On Linux, by design, the system hides all the hardware-specific stuff.   You might THINK you're doing a CPUID instruction, but all the hardware-dependent instructions generate an invisible trap to the kernel, which is free to do anything it wants.  Now in several cases, the kernel kinda emulates the instruction if it's not a dangerous one.  For example, there's not much harm in revealing some of the CPU attributes with CPUID.   But then again, no  guarantees.   The kernel might decide to present the CPU as a generic one, with some default and unrealistic values for its features.

Even if the kernel gives you some ACPID information, you generally can't do anything useful with this information.  Linux will most certainly not let you poke or peek at the control registers.    All low-level device control must be done  by the kernel and associated drivers.  users are not allowed to change critical system values as that will likely destabilize or crash the whole system.

You need to do a major rethink of what your goal is and design a way to accomplish it on Linux.  You can't just blindly convert this kind of code from Windows to Linux.



Author

Commented:
Hi,

Ok, agreed, but we can use something like:

The sample C program:

#include <stdio.h>
#define WORD_EAX  0
#define WORD_EBX  1
#define WORD_ECX  2
#define WORD_EDX  3
#define WORD_NUM  4

#define INITIAL_APIC_ID_BITS 0xFF000000

int get_APICID(){

        unsigned int words[WORD_NUM];
        unsigned int reg = 1;
        __asm__ ("pushl %%ebx      \n\t"        /* save %ebx */
                       "cpuid            \n\t"
                       "movl %%ebx, %1   \n\t"      /* save what cpuid just put in %ebx */
                       "popl %%ebx       \n\t"          /* restore the old %ebx */
                       : "=a" (words[WORD_EAX]),      /* output */
                         "=b" (words[WORD_EBX]),
                         "=c" (words[WORD_ECX]),
                        "=d" (words[WORD_EDX])
                       : "a" (reg));                               /* input */

                return ((words[WORD_EBX] & INITIAL_APIC_ID_BITS) >> 24);
}

found at : http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well

but still i am getting an error: error: can't find a register in class `BREG' while reloading `asm'

Could you suggest where did i go wrong ? even though the site says its correct program?

Thanks in advance for your help.


 

 

CERTIFIED EXPERT
Top Expert 2009
Commented:
>> >> its not giving me the same output ?
>> 
>> Can you show both values ?

I asked this earlier, and you haven't answered it.

I just tried running it on an x86_64 machine (AMD64) running Gentoo Linux, and the code I posted in my first post works fine. It returns 0, which is the expected APIC id for a single core, single processor system, which it is (I also verified that APIC and cpuid are enabled in the kernel).

Also check this document, which explains why this is the expected value :

        http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf
Duncan RoeSoftware Developer
CERTIFIED EXPERT

Commented:
I just ran Infinity08's code on my dual processor, single core system and it returned a value of 1. Nice job
CERTIFIED EXPERT
Top Expert 2009

Commented:
As I tried to explain a few times, the original code I posted in http:#20741653 should work fine.

I suspect however that the author misinterpreted the returned value (as explained in http:#20805023). There's no confirmation of that, since the author never really responded to any of my comments about that.

Furthermore, grg99's post http:#20745939 points out that your kernel has to support retrieving that information (just enable APIC and cpuid in it). And duncan_roe gives an alternative approach in http:#20747117.

So, to re-cap, I recommend a PAQ for :

http:#20741653 (Infinity08)
http:#20745939 (grg99)
http:#20747117 (duncan_roe)
http:#20805023 (Infinity08)

Explore More ContentExplore courses, solutions, and other research materials related to this topic.