Jak mogę zarezerwować blok pamięci z jądra systemu Linux?


26

Mam urządzenie, które potrzebuje bloku pamięci zarezerwowanego wyłącznie dla niego, bez ingerencji systemu operacyjnego. Czy jest jakiś sposób, aby poinformować BIOS lub system operacyjny, że blok pamięci jest zarezerwowany i nie wolno go używać?

Używam tego urządzenia na maszynie openSUSE.

Odpowiedzi:


24

To, o co prosisz, nazywa się DMA. Musisz napisać sterownik, aby zarezerwować tę pamięć.

Tak, zdaję sobie sprawę, że powiedziałeś, że nie chcesz, aby system operacyjny interweniował, a sterownik staje się częścią systemu operacyjnego, ale przy braku rezerwacji sterownika jądro uważa, że ​​cała pamięć należy do niego. (Chyba że powiesz jądru, aby zignorowało blok pamięci, zgodnie z odpowiedzią Aarona).

Rozdział 15 (PDF) „ Linux Device Drivers, 3 / e ” autorstwa Rubini, Corbet i Kroah-Hartmann obejmuje DMA i powiązane tematy.

Jeśli chcesz wersję HTML, znalazłem drugą wersję rozdziału w innym miejscu w Internecie. Uważaj, że druga edycja ma już ponad dekadę, ponieważ pojawiła się, gdy jądro 2.4 było nowe. Od tego czasu dużo pracy poświęcono podsystemowi zarządzania pamięcią jądra, więc może już nie mieć zastosowania.


Czy w DMA mogę wybrać, jakich adresów fizycznych użyć? Czy jądro da mi ciągły blok pamięci? Czy gwarantuje to, że będzie zawsze dostępna?
Nathan Fellman

1
Odpowiedzi na twoje pytania zaczynają się na stronie 442 pliku PDF, na który wskazałem.
Warren Young

25

Jeśli chcesz, aby system operacyjny całkowicie go zignorował, musisz zrobić dziurę w pamięci, używając „ memmap.” Zobacz to odniesienie . Na przykład, jeśli chcesz 512 M na barierze 2 GB, możesz umieścić „ memmap=512M$2G” w wierszu poleceń jądra.

Musisz to sprawdzić, dmesgaby znaleźć ciągłą dziurę do kradzieży, aby nie tupać na żadnym urządzeniu; specyficzne dla twoich płyt głównych + kart.

To nie zalecanym sposobem robienia rzeczy - patrz odpowiedź na Warrena Younga, jak prawidłowo zrobić (sterowniki jądra + DMA). Odpowiadam na dokładnie zadane pytanie. Jeśli planujesz zrobić to dla użytkowników końcowych, będą cię nienawidzić , jeśli zrobisz to im ... zaufaj mi, to jedyny powód, dla którego znałem tę odpowiedź.


Edycja: Jeśli używasz grub2 w / grubby (np. CentOS 7), musisz upewnić się, że uciekasz przed $ . Powinien być \wcześniej jeden $. Przykład:

$ sudo -v
$ sudo grubby --update-kernel=ALL --args=memmap='128M\\$0x57EF0000'
$ sudo grubby --info $(sudo grubby --default-kernel) | grep memmap
args="ro crashkernel=auto ... memmap=128M\$0x57EF0000"

1
Podczas gdy twoja odpowiedź bezpośrednio odpowiada na moje pytanie, odpowiedź Warrena wydaje się być lepszym sposobem na rozwiązanie tego problemu. :-)
Nathan Fellman

1
@WarrenYoung mam żadnego pojęcia, co mają robić z nim. Zgadłbym uint8_t *ptr = 0x8000000z moim przykładem? Albo to może segregować ... Hę, naprawdę nie wiem. Znów znałem odpowiedź, ponieważ byłem użytkownikiem końcowym źle zaprojektowanej karty PCI, w której musiałem ręcznie przydzielić bufor poniżej znaku 4G, a następnie powiedzieć sterownikowi, gdzie jest ta przestrzeń; może nie być to możliwe z obszaru użytkownika.
Aaron D. Marasco

2
Tylko na uśmiechy, zagłębiłem się w to i wydaje się, że potrzebujesz MMAP_FIXED | MMAP_ANON. Bez tutaj niestandardowego urządzenia DMA do zabawy, nie mogę powiedzieć, czy faktycznie robi to, czego chciał OP, ale moje pudełko CentOS szczęśliwie dało mi 8 MB bloku przy 512 MB, kiedy powiedziałem memmap=8M$512Mw GRUB. Nie wymaga nawet dostępu do roota, jak się obawiałem. Ale nawet jeśli robi to dobrze, nadal myślę, że prawdopodobnie będziesz potrzebował sterownika do obsługi przerwań i tym podobnych.
Warren Young

3
@ AaronD.Marasco: Nie, mmap()strony są zerowane, zanim kod obszaru użytkownika je zobaczy. Robi się to dla bezpieczeństwa, aby dane nie wyciekły z jednego procesu do drugiego. Kolejny powód do korzystania ze sterownika, ponieważ może być konieczne zachowanie zawartości bufora DMA w czasie ładowania sterownika. Aha, nawiasem mówiąc, dowolnie umiejscowione mmap()wywołanie kończy się powodzeniem nawet bez memmapopcji rozruchu jądra, przynajmniej tak długo, jak długo nikt nie używa pamięci znajdującej się w miejscu, o które prosiłeś. Opcja rozruchu niewątpliwie zwiększa szanse na sukces, ale nie jest to absolutnie konieczne.
Warren Young,

1
@ AaronD.Marasco hmm, dobrze. ciekawy. dziękuję za ten link, to dobra lektura.
Woodrow Barlow

5

Aby zarezerwować blok pamięci z jądra w systemie Linux opartym na ARM, możesz również użyć reserved-memorywęzła w pliku drzewa urządzeń (dts). W dokumentacji jądra (patrz tutaj ) jest przykład:

memory {
    reg = <0x40000000 0x40000000>;
};

reserved-memory {
    #address-cells = <1>;
    #size-cells = <1>;
    ranges;

    /* global autoconfigured region for contiguous allocations */
    linux,cma {
        compatible = "shared-dma-pool";
        reusable;
        size = <0x4000000>;
        alignment = <0x2000>;
        linux,cma-default;
    };

    display_reserved: framebuffer@78000000 {
        reg = <0x78000000 0x800000>;
    };

    multimedia_reserved: multimedia@77000000 {
        compatible = "acme,multimedia-memory";
        reg = <0x77000000 0x4000000>;
    };
};

0

Najpierw wpisz to polecenie, aby sprawdzić bieżące ustawienie:

sysctl vm.min_free_kbytes

Aby zmienić ustawioną wartość, edytuj /etc/sysctl.conf. Poszukaj linii:

vm.min_free_kbytes=12888

Jeśli nie istnieje, utwórz go (wraz z żądaną wartością). Dopuszczalne są następujące wartości:

8192
12288
16384
20480

8M jest wyjątkowo konserwatywny; może wygodnie siedzieć przy 16M. Po zmianie wartości uruchom to i nie jest konieczne ponowne uruchamianie:

sudo sysctl -p

2
Nie usuwaj swoich postów; usuń go lub oflaguj, aby moderator mógł go usunąć.
jasonwryan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.