2010-10-18 13 views
5

Korzystam z następującego kodu, aby ustawić bit cr0, aby wyłączyć pamięć podręczną. Kiedy skompilować tenjak ustawić rejestr kontrolny 0 (cr0) bitów w x86-64 przy użyciu gcc assembly on linux

#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; 
} 

otrzymuję błąd mówiąc, że argumenty są nieważne dla MOV.

Czy ktoś może wskazać mi dobry przewodnik x86-64 Gcc do robienia tego rodzaju rzeczy? Co dokładnie jest nie tak z powyższym kodem?

+0

Czy to działa, jeśli został on złożony poza osadzonym zestawem (utworzyć plik zespołu i złożyć go za pomocą 'gas' lub' nasm')? – Jonathan

+0

Przydatne pytanie: http://stackoverflow.com/questions/1108485/disable-l2-l1-caches –

+0

Dlaczego chcesz to zrobić? co próbujesz osiągnąć? – Hasturkun

Odpowiedz

5

Ok, więc w końcu napisałem następujący moduł jądra. Nie jestem pewien, czy to prawda, ponieważ nie obserwuję drastycznego spowolnienia, które powinno towarzyszyć wyłączeniu pamięci podręcznej. Ale to kompiluje i wstawia poprawnie.

Wszelkie wskazówki będą pomocne.

Dzięki!

#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); 
+0

Ok. Właśnie potwierdziłem, że to działa. Musisz również wyłączyć rejestry MTRR przez $ echo "disable = 00"> |/proc/mtrr – sanatana

1

Spróbuj tego: "mov %% CR0, %% eax \ n"

Prosty% jest interpretowane jako argument użytkownika (chyba).

Należy czytać this

+0

__asm__ ("mov \t %% cr0, %% rax; "); To mówi Błąd: zła nazwa rejestru '%% cr0 ' – sanatana

+0

z linku: Istnieją dwa% prefiksów do nazwy rejestru. Pomaga to GCC rozróżnić argumenty i rejestry. operandy mają pojedynczy prefiks% as. – sanatana

+0

Czy jesteś pewien, że nadal jest to nazwa rejestru w wersji 64-bitowej? Kod, który wkleiłem, pochodzi z minikernela, który napisałem. – Thomas

0

Kod kompiluje OK dla mnie na 32-bit x86 bit nie na x86-64 - to z gcc 4.2.1 na Mac OS X:

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

Nie błędy lub ostrzeżenia.

$ 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' 
$ 

Sądzę więc, że istnieją głębsze problemy nie tylko z instrukcją tutaj z ASM na x86-64 mov %eax,%cr0.

Patrząc na x86-64 ISA wydaje się, że prawdopodobnie trzeba coś takiego dla 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; 
} 

ja nie wiem, czy to działa, ale przynajmniej kompiluje/montuje OK:

$ gcc -Wall -m64 cr0.c -o cr0 
$ 
+0

Tak, problem polega na kompilacji na x86-64. Użyłem% rax zamiast% eax. Kompiluje dobrze, ale usuwa błędy, gdy go uruchomię. – sanatana

2

Nie można wykonywać takich operacji na podstawie kodu użytkownika, a nawet uruchamiać, ponieważ root jest kodem użytkownika.

Będziesz musiał zrobić to w module sterownika i załadować go za pomocą programu insmod.

+0

OK, spróbuję tego, pisząc to jako moduł! Dzięki Zan. – sanatana

3

myślę, że nie widzą „drastyczne spowolnienie”, bo masz wiele rdzeni, prawda? Zrobiłem kilka eksperymentów i wydaje mi się, że ustawienie CD w% cr0 wpływa tylko na procesor, na którym uruchamiasz moduł.

Upewnij się, że uruchamiasz kod na wszystkich rdzeniach, w których chcesz wyłączyć buforowanie. Można na przykład utworzyć plik/proc/cachedisable, w którym odczyt uruchamia twój kod. Następnie użyj opcji

, aby wyłączyć pamięć podręczną CPU cpu_number. Zrób to samo z/proc/cacheenable i masz wszystko, czego potrzebujesz. To działa dla mnie i nie ma potrzeby zmiany MTRR, co jest dość skomplikowane.Jeśli masz wiele procesorów, możesz wyłączyć buforowanie tylko na jednym z nich i przeprowadzić eksperymenty na tym procesorze. Pozostała część systemu pozostaje użyteczna.

Powiązane problemy