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 une ISR, où sera-t-elle stockée ? Est-ce que chaque processus a sa propre pile noyau ? Comment le processus se coordonne-t-il entre ces deux piles ?
Réponses
Trop de publicités?
- Quelle est la différence entre la pile du noyau et la pile de l'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 des pointeurs de pile), et généralement des protections d'accès à la mémoire différentes. C'est-à-dire que lors d'une 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é par le code du noyau (sous Linux, à travers des fonctions comme copy_from_user()
), la mémoire utilisateur (y compris la pile utilisateur) n'est généralement pas directement accessible.
- 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 de l'espace utilisateur peuvent faire de leur pile (pointeur) ce qu'ils veulent, et il n'y a généralement aucune exigence architecturale pour en avoir une valide. Le noyau ne peut donc pas confiance le pointeur de pile de l'espace utilisateur n'est ni valide ni utilisable, et il faudra donc en définir un sous son propre contrôle. Les différentes architectures de CPU mettent cela en œuvre de différentes manières ; les CPU x86 commutent automatiquement les pointeurs de pile lors des changements de mode de privilège, et les valeurs à utiliser pour les différents niveaux de privilège sont configurables - par le code privilégié (c'est-à-dire uniquement le noyau).
- 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) fait no accrocher les ISR directement à l'architecture x86. portes d'interruption mais délègue la répartition des interruptions à un mécanisme commun d'entrée/sortie d'interruption du noyau qui sauvegarde l'état des registres de pré-interruption avant d'appeler le(s) gestionnaire(s) enregistré(s). Le CPU lui-même, lorsqu'il distribue une interruption, peut exécuter un changement de privilège et/ou de pile, et ceci est utilisé/établi par le noyau de sorte que le code d'entrée d'interruption commun peut déjà compter sur la présence d'une pile noyau.
Cela dit, les interruptions qui se produisent pendant l'exécution du code du noyau utiliseront simplement (et continueront à utiliser) la pile du noyau en place à ce moment-là. Cela peut, si les gestionnaires d'interruptions ont des chemins d'appel profondément imbriqués, conduire à 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 du système de fichiers / RAID logiciel étant interrompu par du code réseau avec iptables actif est connu pour déclencher de tels débordements dans les anciens noyaux non accordés ... la solution est d'augmenter la taille de la pile du noyau pour de telles charges de travail).
- Chaque processus possède-t-il sa propre pile de noyau ?
Pas seulement chaque processus - chaque rosca a sa propre pile noyau (et, en fait, sa propre pile utilisateur également). Souvenez-vous que la seule différence entre les processus et les threads (pour Linux) est le fait que plusieurs threads peuvent partager un espace d'adressage (formant un processus).
- Comment le processus est-il coordonné entre ces deux piles ?
Pas du tout - il n'en a pas besoin. L'ordonnancement (comment et quand les 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 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 telles que makecontext()
o pthread_create()
permettent à l'appelant de spécifier une région de mémoire à utiliser pour la pile du thread "enfant"), ou hérité (par clonage de la mémoire à l'accès, généralement appelé "copy on write" / COW, lors de la création d'un nouveau processus).
Cela dit, le processus puede influencer l'ordonnancement de ses threads et/ou influencer la contexte (état, parmi lequel se trouve le pointeur de pile du thread). Il existe de multiples façons de le faire : Les signaux UNIX, setcontext()
, pthread_yield()
/ pthread_cancel()
, ... - mais cela s'éloigne un peu de la question initiale.
Ma réponse est collectée à partir d'autres questions de l'OS 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 protégé des programmes utilisateurs erronés. Supposons que vous gardiez la même pile pour le noyau et l'espace utilisateur, et qu'un simple défaut de segmentation dans l'application utilisateur fasse planter le noyau et nécessite un redémarrage.
Il y a une "pile noyau" par CPU comme la pile ISR et une "pile 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 pile est nécessaire pour traiter les appels de fonction et les variables locales, comme dans 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 séparée uniquement si le matériel le supporte. Sinon, les trames de la pile ISR sont poussées sur la pile du thread interrompu.
L'espace utilisateur ne sait pas et, franchement, ne se soucie pas de savoir si l'interruption est servie dans la pile du noyau du processus actuel ou dans une pile ISR séparée. Comme les interruptions viennent par processeur, la pile ISR doit ê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 semble excellente.
- Quelle est la différence entre la pile du noyau et la pile de l'utilisateur ?
En se référant à l'ouvrage de Robert Love, Linux Kernel Development, la principale différence est la taille :
L'espace utilisateur peut s'en tirer en allouant statiquement de nombreuses variables sur la pile, notamment d'énormes structures et des tableaux à mille éléments.
Ce comportement est légal car l'espace utilisateur a une grande pile qui peut croître dynamiquement.
La pile du noyau n'est ni grande ni dynamique ; elle est petite 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 niveau de configurable au moment de la compilation et peut être de 4KB ou 8KB.
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.
La pile du noyau contient également un pointeur vers la structure thread_info qui contient des informations sur le thread.