2012-08-09 8 views
13

Mam prosty program, który próbuje uzyskać dostęp do pamięci fizycznej w przestrzeni użytkownika, gdzie jądro przechowuje 1. stronę struktury. Na komputerze 64 bitowym ten adres:Jak uzyskać dostęp do mmaped/dev/mem bez awarii jądra Linux?

  • jądro wirtualny adres: ffffea0000000000
  • adres fizyczny: 0000620000000000

Próbuję uzyskać dostęp do tego adresu fizycznego poprzez mmap w przestrzeni użytkownika. Ale następujący kod powoduje awarię jądra.

int *addr; 
if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0) { 
    printf("Error opening file. \n"); 
    close(fd); 
    return (-1); 
} 
/* mmap. address of first struct page for 64 bit architectures 
* is 0x0000620000000000. 
*/ 
addr = (int *)mmap(0, num*STRUCT_PAGE_SIZE, PROT_READ, MAP_PRIVATE, 
      fd, 0x0000620000000000); 
printf("addr: %p \n",addr); 
printf("addr: %d \n",*addr); /* CRASH. */ 
+1

Jaka jest wartość parametru mmap() w addr? – BjoernD

+1

@BjoernD: Próbowałem powyższego na 32-bitowym x86 (zastępując mmap offset jako 0x01000000); addr = 0xffffffff. I tak, to oczywiście zawiesza się na dereferencji. Jakie jest rozwiązanie? – kaiwan

+3

0xffffffff == -1 -> mmap() zwraca błąd. Zgodnie ze stroną man, przyczyna błędu jest podana w zmiennej "errno". Więc możesz chcieć sprawdzić tat. – BjoernD

Odpowiedz

18

Chyba znalazłem problem - to robić z/dev/mem ochrony mapowania pamięci na x86.

Pl odnoszą się do tego artykułu LWN: "x86: wprowadzenia ograniczeń/dev/mem z opcją config" http://lwn.net/Articles/267427/

CONFIG_NONPROMISC_DEVMEM

Teraz (i przetestowane na jądrze 3.2.21 niedawno) , opcja konfiguracji wydaje się mieć nazwę CONFIG_STRICT_DEVMEM.

zmieniłem config jądra:

$ grep DEVMEM .config 
# CONFIG_STRICT_DEVMEM is not set 
$ 

Gdy wyżej prg był prowadzony z poprzedniego jądra z CONFIG_STRICT_DEVMEM SET: dmesg pokazuje:

[29537.565599] Program a.out tried to access /dev/mem between 1000000->1001000. 
[29537.565663] a.out[13575]: segfault at ffffffff ip 080485bd sp bfb8d640 error 4 in a.out[8048000+1000] 

To właśnie z powodu ochrona jądra ..

Kiedy jądro zostało przebudowane (z CONFIG_STRICT_DEVMEM UNSET) i powyżej PRG został uruchomiony:

# ./a.out 
mmap failed: Invalid argument 
# 

To dlatego, że parametr 'przesunięcie' jest> 1 MB (nieprawidłowy na x86) (było 16MB).

Po wykonaniu mmap przesunięcia się w ciągu 1 MB:

# ./a.out 
addr: 0xb7758000 
*addr: 138293760 
# 

To działa! Zobacz powyższy artykuł LWN, aby uzyskać szczegółowe informacje.

Na architekturach x86 z obsługą PAT (Tabela atrybutów strony) jądro nadal zapobiega mapowaniu regionów DRAM. Powodem tego, jak wspomniano w kernel source jest:

This check is nedded to avoid cache aliasing when PAT is enabled 

Kontrola ta spowoduje błąd podobny do wspomnianego powyżej. Na przykład:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

To ograniczenie można usunąć, wyłączając PAT. PAT można wyłączyć, dodając argument "nopat" do wiersza komend jądra przy starcie systemu.

+0

Cześć Kaiwan, Dzięki za wskazanie interesującej zmiennej konfiguracyjnej. "CONFIG_STRICT_DEVMEM nie jest ustawione" w moim przypadku. Kernel (3.4.6 i 3.1.0). Po dokonaniu zmiany offsetu program działa. Byłem jednak zainteresowany uzyskaniem dostępu do tego adresu, ponieważ zawiera on pierwszą stronę struktury. czy to możliwe? – Vinay

+0

Ustawiłem także przesunięcie na 0x0000000000000000 i otrzymam poprawny adres zwrotny. Ale jeśli ustawię przesunięcie na jakiś losowy adres, na przykład 0x00000000000000ff, nie otrzymam poprawnego adresu. Czy muszę ustawić adres na granicy strony? – Vinay

+1

ARM wymaga użycia granicy strony dla mmap(). Od małego testowania na IA32 wydaje się, że tak też jest w tym przypadku ... (i próbowałem na X86_64, jak zakładam). Również, skomentuj swój dostęp do pierwszej strony struktury, z CONFIG_STRICT_DEVMEM Off, myślałem, że to zadziała (na granicy strony) .. nie jestem pewien o tym .. – kaiwan

3

W architekturach x86 z obsługą PAT (Tabela atrybutów stron) jądro może zapobiegać odwzorowaniu regionów DRAM (nawet jeśli jest skompilowane bez ustawienia CONFIG_NONPROMISC_DEVMEM).

Powodem tego, jak wspomniano w kernel source jest:

This check is nedded to avoid cache aliasing when PAT is enabled 

Kontrola ta spowoduje podobny błąd do stawienia się w dmesg jak te wymienione powyżej powyżej w odpowiedzi kaiwan użytkownika. Na przykład:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

To ograniczenie można usunąć, wyłączając PAT.

PAT można wyłączyć, dodając argument nopat do linii poleceń jądra podczas startu systemu.

+0

Ta (poprawna!) Odpowiedź wydaje się być kopią wklejoną w powyższą odpowiedź przez anonimowego użytkownika 8 minut po udzieleniu odpowiedzi. Jeśli chcesz to usunąć, daj mi znać, a ja to zredaguję, ponieważ uważam to za niesprawiedliwe, jeśli zrobię to bez Twojej zgody. –

+0

To byłem ja. Byłem tym, który dodał ją do poprzedniej odpowiedzi, a następnie dodał ją jako oddzielną odpowiedź, ponieważ (widocznie) nie wiem, jak używać tego narzędzia: D. –

+0

OK! Daj mi znać, jeśli chcesz usunąć to z powyższej odpowiedzi. Twoje zdrowie. –

Powiązane problemy