Kernel-Stack und User Space Stack


110

Was ist der Unterschied zwischen Kernel-Stack und User-Stack? Warum wird der Kernel-Stack verwendet? Wenn eine lokale Variable in einem ISR deklariert ist, wo wird sie gespeichert? Hat jeder Prozess seinen eigenen Kernel-Stack? Wie koordiniert der Prozess dann zwischen diesen beiden Stapeln?

Antworten:


185
  1. Was ist der Unterschied zwischen Kernel-Stack und User-Stack?

Kurz gesagt, nichts - abgesehen von der Verwendung eines anderen Speicherorts im Speicher (und damit eines anderen Werts für das Stapelzeigerregister) und normalerweise unterschiedlichen Speicherzugriffsschutzmaßnahmen. Das heißt, wenn im Benutzermodus ausgeführt wird, ist der Kernelspeicher (ein Teil davon ist der Kernelstapel) nicht zugänglich, selbst wenn er zugeordnet ist. Umgekehrt ist der copy_from_user()Benutzerspeicher (einschließlich des Benutzerstapels) normalerweise nicht direkt zugänglich , ohne dass dies ausdrücklich vom Kernel-Code angefordert wird (unter Linux über Funktionen wie ).

  1. Warum wird [ein separater] Kernel-Stack verwendet?

Trennung von Privilegien und Sicherheit. Zum einen können Userspace-Programme ihren Stapel (Zeiger) beliebig gestalten, und es gibt normalerweise keine architektonischen Anforderungen, um überhaupt einen gültigen zu haben. Der Kernel kann daher nicht darauf vertrauen, dass der Stack-Zeiger des Benutzerbereichs gültig oder verwendbar ist, und benötigt daher einen Satz unter seiner eigenen Kontrolle. Unterschiedliche CPU-Architekturen implementieren dies auf unterschiedliche Weise. x86-CPUs wechseln automatisch die Stapelzeiger, wenn Berechtigungsmoduswechsel auftreten, und die Werte, die für verschiedene Berechtigungsstufen verwendet werden sollen, können konfiguriert werden - durch privilegierten Code (dh nur den Kernel).

  1. Wenn eine lokale Variable in einem ISR deklariert ist, wo wird sie gespeichert?

Auf dem Kernel-Stack. Der Kernel (Linux - Kernel, das ist) ist nicht ISRs direkt mit der x86 - Architektur des hook Interrupt - Gattern sondern delegiert die Interrupt - Dispatch auf einen gemeinsamen Kern Interrupt Ein- / Ausstiegsmechanismus, der Registerzustand vor-Interrupt speichert , bevor die registrierte Handler Aufruf (e) . Die CPU selbst führt beim Auslösen eines Interrupts möglicherweise ein Privileg und / oder einen Stack-Switch aus. Dieser wird vom Kernel verwendet / eingerichtet, sodass der allgemeine Interrupt-Eintragscode bereits davon ausgehen kann, dass ein Kernel-Stack vorhanden ist.
Das heißt, Interrupts, die während der Ausführung des Kernel-Codes auftreten, verwenden einfach (weiterhin) den an diesem Punkt vorhandenen Kernel-Stack. Dies kann, wenn Interrupt-Handler tief verschachtelte Aufrufpfade haben, zu Stapelüberläufen führen (wenn ein tiefer Kernel-Aufrufpfad unterbrochen wird und der Handler einen anderen tiefen Pfad verursacht; unter Linux wird der RAID-Code von Dateisystem / Software durch Netzwerkcode mit aktiven iptables unterbrochen Es ist bekannt, dass dies in nicht abgestimmten älteren Kerneln ausgelöst wird. Die Lösung besteht darin, die Größe des Kernelstapels für solche Workloads zu erhöhen.

  1. Hat jeder Prozess seinen eigenen Kernel-Stack?

Nicht nur jeder Prozess - jeder Thread hat seinen eigenen Kernel-Stack (und tatsächlich auch seinen eigenen User-Stack). Denken Sie daran, dass der einzige Unterschied zwischen Prozessen und Threads (für Linux) darin besteht, dass mehrere Threads einen Adressraum gemeinsam nutzen können (einen Prozess bilden).

  1. Wie koordiniert der Prozess zwischen diesen beiden Stapeln?

Überhaupt nicht - es muss nicht. Die Planung (wie / wann verschiedene Threads ausgeführt werden, wie ihr Status gespeichert und wiederhergestellt wird) ist die Aufgabe des Betriebssystems, und die Prozesse müssen sich nicht damit befassen. Wenn Threads erstellt werden (und jeder Prozess muss mindestens einen Thread haben), erstellt der Kernel Kernel-Stacks für sie, während Userspace-Stacks entweder explizit erstellt / bereitgestellt werden, je nachdem, welcher Mechanismus zum Erstellen eines Threads verwendet wird (Funktionen wie makecontext()oder pthread_create()erlauben es dem Aufrufer Geben Sie einen Speicherbereich an, der für den Stapel des "untergeordneten" Threads verwendet oder geerbt werden soll (durch Klonen des Speichers beim Zugriff, normalerweise als "Kopieren beim Schreiben" / COW bezeichnet, wenn ein neuer Prozess erstellt wird).
Das gesagt, (Status, unter) das ist der Stackpointer Thread) Es gibt mehr Möglichkeiten hierfür:. UNIX - Signale setcontext(), pthread_yield()/ pthread_cancel(), ... - aber das ein wenig von der ursprünglichen Frage ist schweife ab.


Hervorragende Antworten FrankH. Vielen Dank.
Kumar

1
@FrankH Ausgezeichnete Antwort .. aber ich habe kleine Fragen dazu, aber in der ARM-Architektur .. Wie hängt dieser Kernel-Stack mit dem unterschiedlichen Prozessormodus zusammen?
Rahul

2
@ Rahul: "Der Rand eines SO-Kommentars ist zu klein, um eine solche Antwort zu enthalten". Wie Stacks / Stackpointer-Register in den verschiedenen ARM-CPU-Modi funktionieren (welche implementieren einen Banked SP), ist eine gute Frage, erfordert jedoch mehr Platz zum Beantworten, als ein Kommentar geben kann. Gleiches gilt für Dinge wie x86-Task-Gates oder ISTs - es gibt keinen "einzelnen" Kernel-Stack-Zeiger (so wie es keinen "einzelnen" User-Stack-Zeiger gibt) und für welche Hardwareunterstützung / welches Mandat es gibt Separate Stapelzeiger in verschiedenen Betriebsarten sind ... sehr hardwareabhängig.
FrankH.

@FrankH. Ich habe eine neue Frage für das gleiche erstellt ... stackoverflow.com/q/22601165/769260 Ich hoffe, jetzt können Sie mir helfen, ohne sich um Platz zu kümmern :)
Rahul

1
@FrankH. Können Sie ein Diagramm bereitstellen, das zeigt, wo sich der Kernel-Stack im Speicherlayout eines Prozesses befindet?
Jithin Pavithran

18

Meine Antwort wird aus anderen SO-Fragen mit meinen Sachen gesammelt.

What's the difference between kernel stack and user stack?

Als Kernel-Programmierer wissen Sie, dass der Kernel von fehlerhaften Benutzerprogrammen ausgeschlossen werden sollte. Angenommen, Sie behalten den gleichen Stapel für den Kernel und den Benutzerbereich bei, dann stürzt der einfache Segfault in der Benutzeranwendung den Kernel ab und muss neu gestartet werden.

Es gibt einen "Kernel-Stack" pro CPU wie ISR Stack und einen "Kernel-Stack" pro Prozess. Es gibt einen "Benutzerstapel" für jeden Prozess, obwohl jeder Thread seinen eigenen Stapel hat, einschließlich Benutzer- und Kernel-Threads.

http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html

Why kernel stack is used?

Wenn wir uns also im Kernel-Modus befinden, ist ein Stapelmechanismus erforderlich, um Funktionsaufrufe zu verarbeiten, lokale Variablen, die dem Benutzerraum ähnlich sind.

http://www.kernel.org/doc/Documentation/x86/kernel-stacks

If a local variable is declared in an ISR, where it will be stored?

Es wird im ISR-Stack (IRQSTACKSIZE) gespeichert. Der ISR wird nur dann auf einem separaten Interrupt-Stack ausgeführt, wenn die Hardware dies unterstützt. Andernfalls werden die ISR-Stapelrahmen auf den Stapel des unterbrochenen Threads verschoben.

Der Benutzerbereich weiß nicht und kümmert sich offen gesagt nicht darum, ob der Interrupt im Kernel-Stack des aktuellen Prozesses oder in einem separaten ISR-Stack bereitgestellt wird. Da Interrupts pro CPU auftreten, muss der ISR-Stapel pro CPU erfolgen.

 Does each process has its own kernel stack ?

Ja. Jeder Prozess hat einen eigenen Kernel-Stack.

 Then how the process coordinates between both these stacks?

@ FrankHs Antwort sieht für mich gut aus.


4
  1. Was ist der Unterschied zwischen Kernel-Stack und User-Stack?

In Anlehnung an die Linux-Kernel-Entwicklung von Robert Love ist der Hauptunterschied die Größe:

Der Benutzerraum kann durch statisches Zuweisen vieler Variablen auf dem Stapel davonkommen, einschließlich riesiger Strukturen und Arrays mit tausend Elementen.
Dieses Verhalten ist legal, da der Benutzerbereich einen großen Stapel hat, der dynamisch wachsen kann.
Der Kernel-Stack ist weder groß noch dynamisch. es ist klein und fest in der Größe.
Die genaue Größe des Kernel-Stacks variiert je nach Architektur.
Unter x86 kann die Stapelgröße zur Kompilierungszeit konfiguriert werden und kann entweder 4 KB oder 8 KB betragen.
In der Vergangenheit besteht der Kernel-Stack aus zwei Seiten, was im Allgemeinen bedeutet, dass er bei 32-Bit-Architekturen 8 KB und bei 64-Bit-Architekturen 16 KB beträgt - diese Größe ist fest und absolut.
Jeder Prozess erhält einen eigenen Stapel.

Außerdem enthält der Kernel-Stack einen Zeiger auf die Struktur thread_info, die Informationen zum Thread enthält.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.