GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie weise ich einen DMA-Puffer zu, der von 1 GB HugePages in einem Linux-Kernel-Modul unterstützt wird?

PROBLEM

  1. Wenn Sie einen DMA-Puffer zuweisen oder eine physische Adresse erhalten möchten, geschieht dies normalerweise im Kernel-Bereich, da der Benutzercode niemals mit physischen Adressen herumspielen muss.
  2. Hugetlbfs bietet nur User-Space-Mappings, um 1 GB große Seiten zuzuweisen und virtuelle Adressen des User-Space zu erhalten
  3. Es gibt keine Funktion, um eine virtuelle Benutzer-Hugepage-Adresse einer physischen Adresse zuzuordnen

EUREKA

Aber die Funktion ist vorhanden! Tief im Kernel-Quellcode von 2.6 vergraben liegt diese Funktion zum Abrufen einer Strukturseite von einer virtuellen Adresse, die als "nur zum Testen" markiert und mit #if 0:

blockiert ist
#if 0   /* This is just for testing */
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
{
    unsigned long start = address;
    int length = 1;
    int nr;
    struct page *page;
    struct vm_area_struct *vma;

    vma = find_vma(mm, addr);
    if (!vma || !is_vm_hugetlb_page(vma))
        return ERR_PTR(-EINVAL);

    pte = huge_pte_offset(mm, address);

    /* hugetlb should be locked, and hence, prefaulted */
    WARN_ON(!pte || pte_none(*pte));

    page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];

    WARN_ON(!PageHead(page));

    return page;
}

LÖSUNG:Da die obige Funktion nicht wirklich in den Kernel kompiliert ist, müssen Sie sie zu Ihrer Treiberquelle hinzufügen.

BENUTZERSEITIGER ARBEITSABLAUF

  1. Ordnen Sie 1-GB-Hugepages beim Booten mit den Kernel-Boot-Optionen zu
  2. Rufen Sie get_huge_pages() mit hugetlbfs auf, um den Userspace-Zeiger (virtuelle Adresse) zu erhalten
  3. Übergeben Sie die virtuelle Adresse des Benutzers (normaler Zeiger in unsigned long umgewandelt) an den Treiber ioctl

ARBEITSABLAUF DES KERNEL-TREIBERS

  1. Akzeptiere die virtuelle Benutzeradresse über ioctl
  2. Rufen Sie follow_huge_addr auf, um die Strukturseite zu erhalten*
  3. Rufen Sie page_to_phys auf der Strukturseite* auf, um die physische Adresse zu erhalten
  4. Physische Adresse für Gerät für DMA bereitstellen
  5. Rufen Sie kmap auf der Strukturseite* auf, wenn Sie auch einen virtuellen Kernel-Zeiger wollen

HAFTUNGSAUSSCHLUSS

  • Die obigen Schritte werden einige Jahre später in Erinnerung gerufen. Ich habe den Zugriff auf den ursprünglichen Quellcode verloren. Gehen Sie sorgfältig vor und stellen Sie sicher, dass ich keinen Schritt vergesse.
  • Der einzige Grund, warum dies funktioniert, ist, dass 1 GB große Seiten beim Booten zugewiesen werden und ihre physischen Adressen dauerhaft gesperrt sind. Versuchen Sie nicht, eine virtuelle Benutzeradresse, die nicht 1 GB groß ist, auf eine physische DMA-Adresse abzubilden! Du wirst eine schlechte Zeit haben!
  • Testen Sie Ihr System sorgfältig, um zu bestätigen, dass Ihre 1 GB großen Seiten tatsächlich im physischen Speicher gesperrt sind und dass alles genau funktioniert. Dieser Code hat bei meinem Setup einwandfrei funktioniert, aber hier besteht große Gefahr, wenn etwas schief geht.
  • Dieser Code funktioniert garantiert nur auf x86/x64-Architektur (wobei physikalische Adresse ==Busadresse) und auf Kernel-Version 2.6.XX. In späteren Kernel-Versionen gibt es möglicherweise einen einfacheren Weg, dies zu tun, oder es kann jetzt völlig unmöglich sein.

Dies wird im Kernel-Bereich nicht häufig gemacht, also nicht zu viele Beispiele.

Wie jede andere Seite werden riesige Seiten mit alloc_pages zugewiesen, nach der Melodie:

struct page *p = alloc_pages(GFP_TRANSHUGE, HPAGE_PMD_ORDER);

HPAGE_PMD_ORDER ist ein Makro, das eine Reihenfolge einer einzelnen riesigen Seite in Bezug auf normale Seiten definiert. Das Obige impliziert, dass transparente riesige Seiten im Kernel aktiviert sind.

Dann können Sie den erhaltenen Seitenzeiger auf die übliche Weise mit kmap() abbilden.

Haftungsausschluss:Ich habe es nie selbst ausprobiert, daher müssen Sie möglicherweise etwas herumexperimentieren. Eine Sache, die Sie überprüfen sollten, ist Folgendes:HPAGE_PMD_SHIFT repräsentiert eine Bestellung einer kleineren "riesigen" Seite. Wenn Sie diese riesigen 1-GB-Seiten verwenden möchten, müssen Sie wahrscheinlich eine andere Reihenfolge ausprobieren, wahrscheinlich PUD_SHIFT - PAGE_SHIFT.


Linux
  1. Linux – Wie kann man feststellen, welches Modul den Kernel verschmutzt?

  2. Linux – Ein verdorbener Kernel in Linux?

  3. So erstellen, kompilieren und laden Sie ladbare Linux-LKM-Kernel-Module

  4. Wie kodiere ich ein Linux-Kernel-Modul?

  5. So richten Sie einen periodischen Timer-Callback in einem Linux-Kernel-Modul ein

So laden und entladen Sie Kernel-Module in Linux

Modprobe-Befehl unter Linux

So finden Sie die IP-Adresse unter Linux

So installieren Sie das Modul „Python-Pexpect“ unter Linux

So ändern Sie die MAC-Adresse in Linux

So ändern Sie die IP-Adresse unter Linux