web-dev-qa-db-fra.com

pile de noyau et pile d'espace utilisateur

Quelle est la différence entre la pile du noyau et la pile de l'utilisateur? Pourquoi la pile de 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?

91
jkv
  1. Quelle est la différence entre la pile du noyau et celle de l'utilisateur?

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

  1. Pourquoi utilise-t-on une pile de noyau [séparée]?

Séparation des privilèges et de la sécurité. D'une part, les programmes en espace utilisateur peuvent créer leur pile (pointeur) à leur guise, 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 stackpointer de l'espace utilisateur pour qu'il soit valide ni utilisable, et il faudra donc en installer un sous son propre contrôle. Différentes architectures de CPU implémentent cela de différentes manières. Les processeurs x86 commutent automatiquement les stackpointers en cas de changement de mode de privilège, et les valeurs à utiliser pour différents niveaux de privilège sont configurables, à l'aide d'un 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 (c’est-à-dire le noyau Linux) ne ne raccorde pas les ISR directement aux portes d’interruption de l’architecture x86 mais délègue plutôt l'envoi de l'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 ou les gestionnaires enregistrés. Lors de la distribution d'une interruption, la CPU elle-même peut exécuter un commutateur de privilège et/ou de pile, qui le configure/utilise de manière à ce que le code d'entrée d'interruption commun puisse déjà dépendre de la présence d'une pile du noyau.
Cela dit, les interruptions qui se produisent lors de l’exécution du code du noyau utiliseront (continueront) simplement la pile de noyau en place à ce stade. Cela peut, si les gestionnaires d’interruption ont des chemins d’appel profondément imbriqués, conduire à des débordements de pile (si un chemin d’appel du noyau profond est interrompu et que le gestionnaire crée un autre chemin profond; sous Linux, le code RAID système de fichiers/logiciel interrompu par le code réseau avec iptables actif est La solution connue consiste à augmenter la taille de la pile du noyau pour ces charges de travail).

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

Non seulement chaque processus - chaque thread a sa propre pile de noyau (et, en fait, sa propre pile d'utilisateurs). N'oubliez pas que la seule différence entre les processus et les threads (sous Linux) réside dans 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 sauvegardé et restauré) est la tâche du système d'exploitation et les processus n'ont pas besoin de s'en préoccuper. Au fur et à mesure que les threads sont créés (et chaque processus doit avoir au moins un thread), le noyau crée des piles du 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é (par clonage de la mémoire sur accès, généralement appelé "copie à l'écriture"/COW, lors de la création un nouveau processus).
Cela dit, le processus peut influencer la planification de ses threads et/ou influencer le contexte (état, parmi lequel se trouve le stackpointer du thread). Il y a plusieurs façons de procéder: signaux UNIX, setcontext(), pthread_yield()/pthread_cancel(), ... - mais ceci dégrade un peu la question initiale.

165
FrankH.

Ma réponse est collectée à partir de SO questions avec mes données).

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

En tant que programmeur de noyau, vous savez que le noyau doit être restreint aux programmes utilisateur erronés. Supposons que vous gardiez la même pile pour le noyau et l'espace utilisateur, puis un segfault simple dans l'application utilisateur bloque le noyau et nécessite un redémarrage.

Il existe une "pile de noyau" par processeur, telle que la pile ISR, et une "pile de noyau" par processus. Il existe 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, 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 ne s'exécute sur une pile d'interruptions distincte que si le matériel le prend en charge. Sinon, les cadres de la pile ISR sont placés sur la pile du fil interrompu.

L'espace utilisateur ne sait pas et franchement ne se soucie pas de savoir si l'interruption est servie dans la pile de noyau du processus en cours ou dans une pile ISR distincte. Au fur et à mesure que les interruptions arrivent par unité de processeur, la pile d'ISR doit donc l'être par unité de 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 à ravir.

15
Jeyaram
  1. Quelle est la différence entre la pile du noyau et la pile de l'utilisateur?

En prenant comme référence le développement du noyau Linux de Robert Love, la différence principale est la taille:

L'espace utilisateur peut s'en tirer avec l'allocation statique de nombreuses variables sur la pile, y compris d'énormes structures et des tableaux de milliers d'éléments.
Ce comportement est légal car l’espace utilisateur a une grande pile qui peut croître de manière dynamique.
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.
Sous x86, la taille de la pile est configurable au moment de la compilation et peut être de 4 Ko ou de 8 Ko.
Historiquement, la pile du noyau est composée de deux pages, ce qui implique généralement 8 Ko sur les architectures 32 bits et 16 Ko sur les architectures 64 bits. Cette taille est fixe et absolue.
Chaque processus reçoit sa propre pile.

La pile du noyau contient également un pointeur sur la structure thread_info contenant des informations sur le thread.

3
arenard