pile de noyau et pile d'espace utilisateur

110

Quelle est la différence entre la pile du noyau et la pile utilisateur? Pourquoi la pile du noyau est-elle utilisée? Si une variable locale est déclarée dans un ISR, où sera-t-elle stockée? Chaque processus a-t-il sa propre pile de noyau? Alors comment le processus se coordonne entre ces deux piles?

jkv
la source

Réponses:

188
  1. Quelle est la différence entre la pile du noyau et la pile utilisateur?

En bref, rien - à part l'utilisation d'un emplacement différent dans la mémoire (et donc une valeur différente pour le registre de stackpointer), et généralement différentes protections d'accès à la mémoire. C'est-à-dire que lors de l'exécution en mode utilisateur, la mémoire du noyau (dont une partie est la pile du noyau) ne sera pas accessible même si elle est mappée. Vice versa, sans être explicitement demandée par le code du noyau (sous Linux, via des fonctions comme copy_from_user()), la mémoire utilisateur (y compris la pile utilisateur) n'est généralement pas directement accessible.

  1. Pourquoi une pile de noyau [distincte] est-elle utilisée?

Séparation des privilèges et de la sécurité. D'une part, les programmes de l'espace utilisateur peuvent faire de leur pile (pointeur) tout ce qu'ils veulent, et il n'y a généralement aucune exigence architecturale pour même en avoir une valide. Le noyau ne peut donc pas faire confiance au pointeur de pile de l'espace utilisateur pour être valide ou utilisable, et par conséquent nécessitera un ensemble sous son propre contrôle. Différentes architectures de CPU implémentent cela de différentes manières; Les processeurs x86 commutent automatiquement de pointeur de pile lorsque des commutations de mode de privilège se produisent, et les valeurs à utiliser pour différents niveaux de privilège sont configurables - par code privilégié (c'est-à-dire uniquement le noyau).

  1. Si une variable locale est déclarée dans un ISR, où sera-t-elle stockée?

Sur la pile du noyau. Le noyau (noyau Linux, c'est-à-dire) n'accroche pas les ISR directement aux portes d'interruption de l'architecture x86, mais délègue à la place l'envoi d'interruption à un mécanisme commun d'entrée / sortie d'interruption du noyau qui enregistre l'état du registre de pré-interruption avant d'appeler le (s) gestionnaire (s) enregistré (s) . Le processeur lui-même lors de la distribution d'une interruption peut exécuter un privilège et / ou un commutateur de pile, et ceci est utilisé / configuré par le noyau de sorte que le code d'entrée d'interruption commun puisse déjà compter sur la présence d'une pile de noyau.
Cela dit, les interruptions qui se produisent lors de l'exécution du code du noyau utiliseront simplement (continueront) d'utiliser la pile du noyau en place à ce stade. Cela peut, si les gestionnaires d'interruption ont des chemins d'appels profondément imbriqués, entraîner des débordements de pile (si un chemin d'appel profond du noyau est interrompu et que le gestionnaire provoque un autre chemin profond; sous Linux, le code RAID du système de fichiers / logiciel est interrompu par le code réseau avec iptables actif est connu pour déclencher une telle situation dans les noyaux plus anciens non réglés ... la solution est d'augmenter la taille de la pile du noyau pour de telles charges de travail).

  1. Chaque processus a-t-il sa propre pile de noyau?

Pas seulement chaque processus - chaque thread a sa propre pile de noyau (et, en fait, sa propre pile d'utilisateurs également). N'oubliez pas que la seule différence entre les processus et les threads (sous Linux) est le fait que plusieurs threads peuvent partager un espace d'adressage (formant un processus).

  1. Comment le processus se coordonne-t-il entre ces deux piles?

Pas du tout - ce n'est pas nécessaire. La planification (comment / quand différents threads sont exécutés, comment leur état est enregistré et restauré) est la tâche du système d'exploitation et les processus n'ont pas besoin de se préoccuper de cela. Au fur et à mesure que les threads sont créés (et que chaque processus doit avoir au moins un thread), le noyau crée des piles de noyau pour eux, tandis que les piles de l'espace utilisateur sont soit explicitement créées / fournies par le mécanisme utilisé pour créer un thread (fonctions comme makecontext()ou pthread_create()permettent à l'appelant de spécifier une région mémoire à utiliser pour la pile du thread "enfant"), ou héritée (par clonage de mémoire à l'accès, généralement appelé "copie en écriture" / COW, lors de la création d'un nouveau processus).
Cela dit,(état, parmi lesquels se trouve le pointeur de pile du thread). Il y a plusieurs façons pour cela: signaux UNIX, setcontext(), pthread_yield()/ pthread_cancel()... - mais cela est disgressing un peu de la question initiale.

FrankH.
la source
Excellentes réponses FrankH. Merci.
kumar
1
@FrankH Excellente réponse .. mais j'ai des petites questions à ce sujet, mais dans l'architecture ARM .. Comment cette pile de noyau est-elle liée aux différents modes de processeur?
Rahul
2
@Rahul: "la marge d'un commentaire SO est trop petite pour contenir une telle réponse". Le fonctionnement des piles / registres de pointeur de pile dans les différents modes du processeur ARM (lesquels implémentent un SP mis en banque) est une bonne question, mais nécessite plus d'espace pour répondre qu'un commentaire ne peut en donner. Il en va de même pour des éléments tels que les portes de tâches x86 ou les IST - il n'y a pas de pointeur de pile de noyau «unique» (tout comme il n'y a pas de pointeur de pile utilisateur «unique»), et quel support / mandat matériel il y a pour les pointeurs de pile séparés dans différents modes de fonctionnement sont ... très dépendants du matériel.
FrankH.
@FrankH. J'ai créé une nouvelle question pour la même ... stackoverflow.com/q/22601165/769260 J'espère que maintenant vous pouvez m'aider sans vous soucier de l'espace :)
Rahul
1
@FrankH. Pouvez-vous fournir un diagramme montrant à quoi appartient la pile du noyau dans la disposition de la mémoire d'un processus?
Jithin Pavithran
19

Ma réponse est collectée à partir d'autres questions SO avec mes affaires.

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

En tant que programmeur du noyau, vous savez que le noyau doit être limité aux programmes utilisateur erronés. Supposons que vous gardiez la même pile pour le noyau et l'espace utilisateur, puis un simple segfault dans l'application utilisateur plante le noyau et doit être redémarré.

Il y a une "pile de noyau" par CPU comme ISR Stack et une "pile de noyau" par Processus. Il y a une "pile utilisateur" pour chaque processus, bien que chaque thread ait sa propre pile, y compris les threads utilisateur et noyau.

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

Why kernel stack is used?

Ainsi, lorsque nous sommes en mode noyau, un mécanisme de type pile est nécessaire pour traiter les appels de fonction, des variables locales similaires à l'espace utilisateur.

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

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

Il sera stocké dans la pile ISR (IRQSTACKSIZE). L'ISR s'exécute sur une pile d'interruptions distincte uniquement si le matériel le prend en charge. Sinon, les cadres de pile ISR sont poussés sur la pile du thread interrompu.

L'espace utilisateur ne sait pas et ne se soucie franchement pas de savoir si l'interruption est servie dans la pile de noyau du processus actuel ou dans une pile ISR séparée. Comme les interruptions viennent par processeur, la pile ISR doit donc être par processeur.

 Does each process has its own kernel stack ?

Oui. Chaque processus a sa propre pile de noyau.

 Then how the process coordinates between both these stacks?

La réponse de @ FrankH me va très bien.

Jeyaram
la source
4
  1. Quelle est la différence entre la pile du noyau et la pile utilisateur

Prenant référence au développement du noyau Linux de Robert Love, la principale différence est la taille:

L'espace utilisateur peut s'en tirer en allouant statiquement de nombreuses variables sur la pile, y compris d'énormes structures et des tableaux de mille éléments.
Ce comportement est légal car l'espace utilisateur a une grande pile qui peut augmenter dynamiquement.
La pile du noyau n'est ni grande ni dynamique; il est petit et de taille fixe.
La taille exacte de la pile du noyau varie selon l'architecture.
Sur x86, la taille de la pile est configurable au moment de la compilation et peut être de 4 Ko ou 8 Ko.
Historiquement, la pile du noyau est de deux pages, ce qui implique généralement qu'elle est de 8 Ko sur les architectures 32 bits et de 16 Ko sur les architectures 64 bits - cette taille est fixe et absolue.
Chaque processus reçoit sa propre pile.

De plus, la pile du noyau contient un pointeur vers la structure thread_info contenant des informations sur le thread.

Arenard
la source