- 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 ).
- 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).
- 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.
- 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).
- 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.