Wie kann ich einen Speicherblock aus dem Linux-Kernel reservieren?

25

Ich habe ein Gerät, das einen Speicherblock benötigt, der ausschließlich für dieses Gerät reserviert ist, ohne dass das Betriebssystem eingreift. Gibt es eine Möglichkeit, dem BIOS oder dem Betriebssystem mitzuteilen, dass ein Speicherblock reserviert ist und nicht verwendet werden darf?

Ich verwende dieses Gerät auf einem openSUSE-Computer.

Nathan Fellman
quelle

Antworten:

23

Was Sie verlangen, heißt DMA. Sie müssen einen Treiber schreiben, um diesen Speicher zu reservieren.

Ja, mir ist klar, dass Sie gesagt haben, Sie wollten nicht, dass das Betriebssystem eingreift, und ein Treiber wird Teil des Betriebssystems, aber ohne eine Fahrerreservierung glaubt der Kernel, dass der gesamte Speicher dazu gehört. (Es sei denn, Sie weisen den Kernel an, den Speicherblock gemäß Aarons Antwort zu ignorieren.)

Kapitel 15 (PDF) von " Linux Device Drivers, 3 / e " von Rubini, Corbet und Kroah-Hartmann behandelt DMA und verwandte Themen.

Wenn Sie eine HTML-Version davon haben möchten, habe ich die zweite Ausgabe des Kapitels an einer anderen Stelle online gefunden. Beachten Sie, dass die 2. Ausgabe bereits über ein Jahrzehnt alt ist, nachdem Kernel 2.4 neu war. Das Speicherverwaltungs-Subsystem des Kernels wurde seit jenen Tagen vielfach überarbeitet, so dass es möglicherweise nicht mehr sehr gut funktioniert.

Warren Young
quelle
Kann ich mit DMA auswählen, welche physischen Adressen verwendet werden sollen? Gibt mir der Kernel einen zusammenhängenden Speicherblock? Ist es garantiert immer verfügbar?
Nathan Fellman
1
Ihre Fragen werden ab Seite 442 des PDF beantwortet, auf das ich Sie hingewiesen habe.
Warren Young
24

Wenn Sie möchten, dass das Betriebssystem es vollständig ignoriert, müssen Sie mit " memmap." Siehe diese Referenz . Wenn Sie beispielsweise 512 MB an der 2-GB-Grenze haben möchten, können Sie " memmap=512M$2G" in die Kernel-Befehlszeile eingeben.

Sie müssen Ihre überprüfen dmesg, um ein zusammenhängendes Loch zu finden, das gestohlen werden kann, damit Sie nicht auf Geräte treten. das ist spezifisch für dein Motherboard + Karten.

Dies ist nicht die empfohlene Vorgehensweise. Informationen zur korrekten Vorgehensweise finden Sie in der Antwort von Warren Young (Kerneltreiber + DMA). Ich beantworte genau die Frage, die Sie gestellt haben. Wenn Sie vorhaben, dies für Endbenutzer zu machen, werden sie Sie hassen , wenn Sie ihnen dies antun ... Vertrauen Sie mir, das ist der einzige Grund, warum ich diese Antwort kannte.


Bearbeiten: Wenn Sie grub2 mit grubby verwenden (z. B. CentOS 7), müssen Sie sicherstellen, dass Sie das $ entkommen . Es sollte \vorher eine Single geben $. Beispiel:

$ 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"
Aaron D. Marasco
quelle
1
Während Ihre Antwort meine Frage direkt beantwortet, scheint Warrens Antwort der bessere Weg zu sein, dies zu tun. :-)
Nathan Fellman
1
@WarrenYoung Ich habe keine Ahnung, was du damit machen sollst. Ich würde " uint8_t *ptr = 0x8000000" mit meinem Beispiel raten ? Oder dass Segfault ... Huh, ich weiß es wirklich nicht. Wieder wusste ich die Antwort, weil ich ein Endbenutzer einer schlecht gestalteten PCI-Karte war, bei der ich manuell einen Puffer unterhalb der 4G-Marke zuweisen und dann einem Fahrer mitteilen musste, wo sich dieser Speicherplatz befand. Es ist möglicherweise nicht möglich, Userland.
Aaron D. Marasco
2
Nur zum Grinsen habe ich etwas tiefer in diese Sache geschaut, und es scheint, dass Sie es brauchen MMAP_FIXED | MMAP_ANON. Ohne ein benutzerdefiniertes DMA-Gerät, mit dem ich hier spielen kann, kann ich nicht sagen, ob es tatsächlich das tut, was das OP wollte, aber meine CentOS-Box hat mir glücklich einen 8-MB-Block mit 512 MB gegeben, als ich dies memmap=8M$512Min GRUB sagte . Es erfordert nicht einmal root-Zugriff, wie ich befürchtet hatte. Aber selbst wenn dies das Richtige tut, werden Sie wahrscheinlich einen Treiber brauchen, um mit Interrupts und ähnlichem umzugehen.
Warren Young
3
@ AaronD.Marasco: Nein, mmap()die Seiten werden auf Null gesetzt, bevor der Userland-Code sie sehen kann. Dies geschieht aus Sicherheitsgründen, damit keine Daten von einem Prozess zum nächsten gelangen. Ein weiterer Grund für die Verwendung eines Treibers, da Sie möglicherweise den Inhalt des DMA-Puffers beim Laden des Treibers beibehalten müssen. Übrigens, der willkürlich lokalisierte mmap()Aufruf ist auch ohne die memmapKernel-Boot-Option erfolgreich, zumindest solange noch niemand den Speicher verwendet, der sich dort befindet, wo Sie gefragt haben. Die Boot-Option erhöht zweifellos die Erfolgschancen, ist aber nicht zwingend erforderlich.
Warren Young
1
@ AaronD.Marasco hmm, okay. interessant. Vielen Dank für diesen Link, es ist eine gute Lektüre.
Woodrow Barlow
5

Um einen Speicherblock aus dem Kernel in ARM-basiertem Linux zu reservieren, können Sie auch einen reserved-memoryKnoten in Ihrer Gerätebaumdatei (dts) verwenden. In der Kernel-Dokumentation (siehe hier ) gibt es ein Beispiel:

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>;
    };
};
Vladimir S.
quelle
0

Geben Sie zuerst diesen Befehl ein, um Ihre aktuelle Einstellung zu überprüfen:

sysctl vm.min_free_kbytes

Um den eingestellten Wert zu ändern, bearbeiten Sie /etc/sysctl.conf. Suchen Sie nach der Zeile:

vm.min_free_kbytes=12888

Wenn es nicht vorhanden ist, erstellen Sie es (zusammen mit Ihrem gewünschten Wert). Folgende Werte sind akzeptabel:

8192
12288
16384
20480

8M ist äußerst konservativ; es kann bei 16m bequem sitzen. Wenn Sie den Wert geändert haben, führen Sie dies aus und es ist kein Neustart erforderlich:

sudo sysctl -p
Michael Mrozek
quelle
2
Bitte löschen Sie Ihre Beiträge nicht. Löschen Sie es oder markieren Sie es, damit ein Moderator es für Sie entfernen kann.
Jasonwryan