Noyau

Le noyau est partie intégrante de tout process. Il est toujours là et s'active de temps en temps pour gérer le système ou permettre l'accès à une ressource (mémoire ou device).

Emplacement mémoire

Le noyau est toujours présent en mémoire. Il est placé aux addresses les plus hautes, qu'on appelle kernel space, par opposition au user space qui contient le process :

kernel space
user space

Sur un adressage de 64b, on réserve le dernier bit pour le noyau (comme un bit de signe) :

Pour les processeurs x86-64, l'adressage ne se fait que sur les 48 premiers bits donc allant des bits 0 à 47 (les bits 48 à 63 sont forcé à être identiques au bit numéro 47), le kernel space est donc déterminé par la valeur du bit numéro 47, l'espace d'adressage total est donc de $2^{48}$B = 256TiB, les user et kernel space se partageant chacun 126TiB (ça va, ya la place).

Process et noyau

On obtient une utilisation de la mémoire suivante, quelque soit le process :

noyau                                  ; accès kernel mode
pile                                   ; accès  user mode
...
bibliothèques partagées                ; accès user mode
...
tas                                    ; accès user mode
données                                ; accès user mode
code                                   ; accès user mode

La partie noyau est protégée par un anneau de protection placé par le processeur. Un process ne peut modifier ou accéder à la mémoire du noyau de lui-même, il doit y être invité par un appel système.

Noyau

Le kernel space (partie où est stockée le noyau) contient :

Pour un adressage sur 48bit : mémoire du noyau

Activation du noyau

Au boot de la machine :

  1. le code du noyau se charge en mémoire
  2. des liens avec le processeur son tissés pour associer des actions du noyau à des évènements systèmes.

Ce sont ces liens qui permettent l'exécution du noyau une fois le boot terminé. Il consistent en des adresses de fonctions à exécuter selon telle ou telle circonstances

Slice de temps

Si le noyau n'a pas été activé depuis un certain laps de temps, il s'active. Ceci est géré par le processeur via le HPET : Lorsqu'un certain laps de temps est passé, une fonction du noyau est appelée (l'adresse de cette fonction est stockée dans un registre du processeur).

C'est un cas particulier d'interruption.

Interruptions

Les interruptions sont des évènements qui nécessitent une réponse immédiate du noyau. Le processeur possède une table qui associe à chaque numéro d'interruption une adresse contenant la fonction du noyau à utiliser.

Il y a 256 interruptions possibles, et sont dépendantes du processeur et du système d'exploitation. On peut les organiser comme suit sous Linux :

Lorsqu'une interruption est déclarée, processeur appelle la fonction du noyau concernée, une interruption pouvant bien sur être elle même interrompue (sauf par une interruptions déjà en cours d'exécution).

Matériel

Les interruptions de 32 à 127 sont générés par le matériel et permettent :

Il n'y a pas de liste proprement dites, puisqu'elles dépendent du matériel.

Exceptions

Les exceptions sont des interruptions spéciales, lancées par le processeur. Il y en a 32 et leur liste est connue : elles vont de la division par 0 (la 0x0), à l’instruction invalide (0x6) à la page fault (0xE).

Appels systèmes

Les appels systèmes permettent à un process d'appeler le noyau. Ils le font en utilisant une instruction spéciale du processeur (syscall) qui appelle une fonction du noyau. Comme pour les interruptions, l'adresse de la fonction à appeler est fixée au boot.

On les utilise pour de multiples raisons, allant de la reservation de mémoire à la demande d'accès à un fichier : à chaque fois qu'un process veut accéder à autre chose que son code ou ses données, il doit le faire fia un appel système.

Signaux

Les signaux permettent à des process de se communiquer des directives. Il y en a toute une liste qui permette de gérer l'action d'un process (se tuer, s'arrêter, reprendre son activité, etc).

La gestion des signaux est asynchrone :

  1. le process A veut envoyer le signal S au process B
  2. il demande (par un appel système) au noyau de le faire : le process A est donc en cours d'exécution
  3. le noyau marque dans sa gestion du process B que la prochaine fois qu'il s'exécutera, il faudra qu'il traite le signal S (on le fait via un flag)
  4. au bout d'un certain temps, lorsque le process B est activé, il devra exécuter sa gestion du signal S

Certains signaux peuvent être ignorées (comme le fait de gérer les touches CTRL+C par exemple), d'autres non (le fait de se tuer violemment (signal SIGKILL) par exemple ne peut être ignorée alors que la demande polie de se tuer (signal SIGTERM), oui).

Fun fact, certains appels systèmes combotent avec des signaux. Par exemple l'appel système qui permet de suspendre son exécution tant que le signal de réveil n'est pas activé (très pratique pour un serveur web qui ne va se réveiller que lorsqu'une requête arrive par exemple).

Gestion de la mémoire

TBD : gérer la mémoire pour que tout ne se collisionne pas

  • par process brk() pour augmenter le tas.