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,
askquestion_expertAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Infinity08Commented:
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

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
askquestion_expertAuthor 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 ?
0
Infinity08Commented:
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 ;)
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

askquestion_expertAuthor Commented:
Ok ,i will it a try and let you know.
0
askquestion_expertAuthor 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,
0
Infinity08Commented:
>> 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 ?
0
askquestion_expertAuthor 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);
   }
}
0
Infinity08Commented:
>> ./neel: Exec format error. Wrong Architecture.

You have to compile on the same machine as you run it ... Did you do that ?
0
Infinity08Commented:
Can you also answer my questions from the post with id 20742593 ?
0
grg99Commented:
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.
0
Duncan RoeSoftware DeveloperCommented:
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)
0
askquestion_expertAuthor 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,
0
Infinity08Commented:
>> 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 ?
0
grg99Commented:
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.



0
askquestion_expertAuthor 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.


 

 

0
Infinity08Commented:
>> >> 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
0
Duncan RoeSoftware DeveloperCommented:
I just ran Infinity08's code on my dual processor, single core system and it returned a value of 1. Nice job
0
Infinity08Commented:
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)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Programming

From novice to tech pro — start learning today.