2015-04-01 9 views
6

Ich schreibe einen Linux-Kernel-Treiber und für jede Funktion, die Daten an Userspace sendet oder Daten aus dem Userspace liest, verwende ich copy_to_user() und copy_from_user(). Meine Frage ist: Muss ich diese Aufrufe verwenden, wenn ich nur einen grundlegenden Datentyp wie eine u32 oder eine int kopieren?copy_to_user() und copy_from_user() für den grundlegenden Datentyp

+0

Es gibt einige Verwirrung über genau das, was Sie fragen. Eine Beispielfunktionsdeklaration, die anzeigt, ob Sie einen "int" oder einen Zeiger an "int" übergeben, wäre hilfreich. Die zwei bisher veröffentlichten Antworten basieren auf zwei verschiedenen Interpretationen Ihrer Frage. –

Antwort

7

Wenn die Funktion einen Zeiger zu Benutzer-Raum-Daten empfängt, haben Sie copy_from_user() verwenden, um die spitz zulauf-Daten aus Anwenderraum in dem Kernel (und umgekehrt) zu kopieren.

Beachten Sie, dass der Zeigerwert selbst als Wert übergeben wird (wie alle C-Parameter). Sie müssen also copy_from_user() nicht ausführen, um den Zeigerwert zu erhalten, bevor Sie auf die Daten zeigen können.

Numerische Argumente funktionieren auf die gleiche Weise wie Zeigerargumente; in C ausgedrückt sind sie beide Skalare. Sie müssen copy_from_user() nicht verwenden, um den Wert des Parameters zu kopieren; das wurde schon kopiert. Sie müssen es nur verwenden, um Daten zu kopieren, auf die ein übergebener Zeiger zeigt.

Wenn Sie also einen Parameter vom Typ int haben, können Sie ihn direkt verwenden. Wenn Ihr Parameter auf int zeigt, befindet sich das Objekt int im Benutzerbereich und Sie müssen copy_to_user verwenden, um den Wert dieses Objekts in den Kernelbereich zu kopieren.

+0

Ich stimme dir nicht zu. Angenommen, ein Zeiger im Benutzerraum ist nicht mit einer Seite ausgerichtet und Sie müssen beide Teile des Zeigers zusammensetzen, um sie vollständig zu machen? Das einzige, was Sie vom Benutzer bereits als Parameter für den Aufruf erhalten, ist der Benutzerzeiger, aber wenn er auf einen anderen Benutzerzeiger zeigt, muß dieser Zeiger mit user_copy erfaßt werden. In 64-Bit-Umgebungen ist ein Benutzerzeiger 8 Byte breit und kann in eine Seitenbegrenzung aufgeteilt werden. Daher müssen Sie auf die virtuellen Seitentabellen zugreifen, um sie vom Benutzerbereich in den Kernel zu übersetzen. Außerdem können User-Space-Seiten ausgelagert werden, also seien Sie vorsichtig damit. –

+0

Wenn Sie sagen, dass der Zeiger nicht page-ausgerichtet ist, meinen Sie, dass das Zeigerobjekt selbst falsch ausgerichtet ist oder die Daten, auf die es zeigt? Zeiger sind Skalare und werden immer nach Wert übergeben. Wenn ein Systemaufruf zum Beispiel einen 'void *' - Parameter hat, empfängt die Kernfunktion, die den Systemaufruf verarbeitet, eine * Kopie * des Zeigers; Die Ausrichtung des Zeigerobjekts auf der Seite des Anrufers ist irrelevant. –

+0

Für Zeiger auf einfache Datentypen (wie 'int *') können auch 'put_user' und' get_user' verwendet werden. – holgac

2

Wenn ein Benutzer Daten an Kernel-Bereich übergibt, können diese Daten auf mehrere Seiten aufgeteilt werden, und diese Seiten können sogar in ausgelagerten Speicher ausgetauscht werden. In diesen Fällen müssen Sie darauf warten, dass der Kernel auf der Seite wechselt und Zugriff auf die Seite erhält, auf der sich die Daten befinden. Bei elementaren Datentypen (wie int oder Zeigern) trifft dies auch auf einige Architekturen zu (Insbesondere x86 Intel) zwingt den Benutzer nicht, die Daten so auszurichten, dass sogar eine Ganzzahl um einen Seitenrand herum aufgeteilt werden kann. Sie können auf den ersten Teil Ihrer Ganzzahl zugreifen, aber darauf warten, dass die zweite vom Speichermanager eingetauscht wird, bevor auf die ganze Sache zugegriffen wird.

Sie können einige Roundtrips speichern, indem Sie alle Benutzerdaten in eine Struktur einfügen, deren Zeiger an den Kernel übergeben wird. Sie können es als Block copy_from_user und Zugriffe speichern (und in die Gefahr zu laufen, blockierten mehrmals des Seins)

So, und als Abschluss, die Funktionen nutzen, auch für Grundtypen, da es viele von ihnen gibt. Nehmen Sie nicht an, wo die Benutzerdaten sein können, wenn sie im Kernel-Modus ausgeführt werden. Sie haben Zugriff darauf, aber die virtuellen Kernel-Adressen von Benutzerdaten haben nichts mit den virtuellen Adressen zu tun, die im Benutzermodus angezeigt werden.

+0

Luis: Ich denke, Sie haben das OP falsch interpretiert. Das gesamte OP versucht, einen einzelnen Wert eines grundlegenden Datentyps zu übergeben. Das OP fragt wirklich, ob es möglich ist, Basisdaten nach Wert anstatt nach Referenz zu übergeben. Wie @Keith darauf hingewiesen hat, wird normalerweise ein Zeiger übergeben, und dieser Zeiger wird als Wert übergeben, so dass direkt darauf zugegriffen werden kann. Wenn Sie jedoch den Benutzerzeiger dereferenzieren möchten, müssen Sie die Funktion copy_from_user() oder get_user() verwenden, wenn Sie sich im Kernel befinden. –

+0

Entschuldigung, aber wie er sagt: * wenn ich nur einen einfachen Datentyp wie u32 oder int * kopiere, also nehme ich an, dass int als Referenz übergeben wird (um zB einen Wert zurückzugeben) wenn er einen Wert nur an den Kernel übergibt (aber nicht zurück an den Benutzerbereich), kann er dies tun. Ich denke nicht an ioctls, wo das Sinn macht. Angenommen, er versucht zu "int"; write (fc, & a, sizeof a); '... –

+0

Natürlich ** kann ** ** der an den Kernelraum übergebene Zeiger in einem ** write (2) ** als Daten verwenden, aber nicht viel Sinn beim Erstellen von a Treiber so. Er sagt * ... und für jede Funktion ... * –

Verwandte Themen