views:

66

answers:

4

I am using the following code to set the cr0 bit to disable cache. When I compile this

#include <stdio.h>

int main()
{
        __asm__("pushl  %eax\n\t"
                "mov    %cr0,%eax;\n\t"
                "orl    $(1 << 30),%eax;\n\t"
                "mov    %eax,%cr0;\n\t"
                "wbinvd\n\t"
                "popl   %eax"
);

        return 0;
}

I am getting error saying that the operands are invalid for mov.

Can anyone please point me to a good gcc x86-64 guide for doing these kinds of things? Also what exactly is wrong with the above code?

A: 

Try this: "mov %%cr0, %%eax \n"

A simple % is interpreted as user argument (I think).

You should read this

Thomas
__asm__ ("mov %%cr0,%%rax;");This says Error: bad register name `%%cr0'
pranith
from the link: There are two %’s prefixed to the register name. This helps GCC to distinguish between the operands and registers. operands have a single % as prefix.
pranith
Are you sure that it is still cr0 the name of the register in 64bit ? The code that I've pasted is from a minikernel that I wrote.
Thomas
Yes, cr0 is the name for control register on x86/x86-64 processors. It is the registers that has changed. Do I need to enter protected mode to access cr0? I am running this exec as root.
pranith
Yes, it is a protected instruction (fortunately :))
Thomas
@pranith, @Thomas: Indeed! No operating system will allow a user program (even root is a user program!) to disable cache, change page tables or any other protected instruction.
Zan Lynx
A: 

The code compiles OK for me on 32-bit x86 bit not on x86-64 - this is with gcc 4.2.1 on Mac OS X:

$ gcc -Wall -m32 cr0.c -o cr0
$

No errors or warnings.

$ gcc -Wall -m64 cr0.c -o cr0
/var/folders/.../cce0FYAB.s:9:suffix or operands invalid for `push'
/var/folders/.../cce0FYAB.s:10:suffix or operands invalid for `mov'
/var/folders/.../cce0FYAB.s:12:suffix or operands invalid for `mov'
/var/folders/.../cce0FYAB.s:14:suffix or operands invalid for `pop'
$

So I guess there are deeper issues than just the mov %eax,%cr0 instruction here with asm on x86-64.

Looking at the x86-64 ISA it seems that you probably need something like this for x86-64:

#include <stdio.h>

int main()
{
        __asm__("pushq  %rax\n\t"
                "movq    %cr0,%rax\n\t"
                "orl    $(1 << 30),%eax\n\t"
                "movq    %rax,%cr0\n\t"
                "wbinvd\n\t"
                "popq   %rax"
);

        return 0;
}

I don't know if this works but it at least compiles/assembles OK:

$ gcc -Wall -m64 cr0.c -o cr0
$ 
Paul R
Yes, the problem is with compiling on x86-64. I used %rax instead of %eax. It compiles fine but seg faults when I run it.
pranith
A: 

You cannot do operations like this from user code and even running as root is user code.

You will need to make this into a driver module and load it using insmod.

Zan Lynx
Ok, I will try this by writing it as a module!Thanks Zan.
pranith
+1  A: 

Ok, so finally I wrote the following kernel module. Am not sure it is right, since I don't observe the drastic slowdown which should accompany when you disable cache. But this compiles and inserts properly.

Any pointers will be helpful.

Thanks!

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
        printk(KERN_ALERT "Hello, world\n");
        __asm__("push   %rax\n\t"
                "mov    %cr0,%rax;\n\t"
                "or     $(1 << 30),%rax;\n\t"
                "mov    %rax,%cr0;\n\t"
                "wbinvd\n\t"
                "pop    %rax"
);
        return 0;
}
static void hello_exit(void)
{
        printk(KERN_ALERT "Goodbye, cruel world\n");
        __asm__("push   %rax\n\t"
                "mov    %cr0,%rax;\n\t"
                "and     $~(1 << 30),%rax;\n\t"
                "mov    %rax,%cr0;\n\t"
                "wbinvd\n\t"
                "pop    %rax"
);
}
module_init(hello_init);
module_exit(hello_exit);
pranith
Ok. I just confirmed that this works. You also need to disable the MTRR registers by $ echo "disable=00" >| /proc/mtrr
pranith