379 views
# Concepts et implémentation appliqués à l’architecture Intel x86 **Ressources annexes** - Wiki OSDev, Wiki de référence pour le fonctionnement des systèmes d’exploitation [wiki.osdev.org](http://wiki.osdev.org/) [Fiche simji](https://notes.ar-lacroix.fr/s/wVxPDfebw#) ## Phase de démarage Le CPU dispose de plusieurs modes, au démarrage, il démarre en mode “**réel**” [https://wiki.osdev.org/Real_Mode](https://wiki.osdev.org/Real_Mode) - Historiquement, l’état initial du CPU - Mode d’exécution 16 bits - Mode d’adressage 20 bits - Intéraction facile avec le BIOS - Accès mémoire non protégé Ce mode permet d’effectuer toutes les opérations bas niveau nécessaire au démarrage de la machine. La première instruction que le CPU exécute est contenue dans la mémoire flash ROM du BIOS, qui est mappe à l’adresse `0xfffffff0` (`max_addr - max_insn_sz`). Puis saut en 0xf0000 (BIOS code area). BIOS : Basic Input Output System ([https://wiki.osdev.org/BIOS](https://wiki.osdev.org/BIOS)) - gère la mémoire - les interruption - les tables ACPI (veille, veille prolongée, gestion de batterie) Ensuite il recherche le boot sector (= marqueur sur un périphérique qui dit que le périphérique est bootable et où commence le code de boot (= MBR), contient 512 octets) : Il maintient une liste de périphériques de démarrage - HDD - Disquettes - Clé USB - … Notions de Boot Sector ([https://wiki.osdev.org/MBR_(x86)](https://wiki.osdev.org/MBR_(x86))) qui contient un saut vers le Boot Loader ([https://wiki.osdev.org/Bootloader](https://wiki.osdev.org/Bootloader)). 📽 Vidéo qui récap le Boot Process : [https://youtu.be/Lp__Y-_DsfU](https://youtu.be/Lp__Y-_DsfU) ⚠️ Boot sector ≠ BIOS Ordre d’importance (en termes de privilèges / criticité) des différentes parties : Microcode ⇒ BIOS ⇒ BootSector ⇒ Bootloader ⇒ OS ⇒ … ## Différents modes : * réel * virtuel 8086 * system management (SMM) * protégé * IA32e (x86-64) * virtualisé (VMX) Les différents modes opératoires : **réel, virtuel, system management (SMM), protégé, IA32 (x86-64), virtualisé (VMX), …** donnent des foncitonnalités et comportements différents. Le CPU est dans **UN** mode à la fois et transitionne entre les environnements d'exécution très différents. Détails sur les différents modes opératoires : [https://wiki.osdev.org/Category:Operating_Modes](https://wiki.osdev.org/Category:Operating_Modes) Certaines instructions CPU ne sont accessibles uniquement dans un mode particulier. Exemple : l’instruction `VMXON` ([https://www.felixcloutier.com/x86/vmxon](https://www.felixcloutier.com/x86/vmxon)) utilisée pour entrer dans une opération VMX n’est accessible qu’en mode “virtualisé”. - mode réel : - 16 bit `ax` - mode protégé - 32 bits `eax` Le CPU utilise différents registres “spéciaux”: - Registres de segments : [https://wiki.osdev.org/CPU_Registers_x86-64#Segment_Registers](https://wiki.osdev.org/CPU_Registers_x86-64#Segment_Registers) selecteur qui permet d'ajouter une adresse de base (qui fera un offset). | | | | --- | --- | | CS | Code Segment | | DS | Data Segment | | SS | Stack Segment | | ES | Extra Segment (used for string operations) | | FS | General-purpose Segment | | GS | General-purpose Segment | - Registres de contrôle (CR0, CR1, CR2, CR3, CR4, …) : [https://wiki.osdev.org/CPU_Registers_x86-64#Control_Registers](https://wiki.osdev.org/CPU_Registers_x86-64#Control_Registers) - Registres de segmentation (gdtr, idtr...) - Model specific Registers ### Les autres modes “Exotiques” - System Management Mode - Mode le plus privilégié - Utilisé par les firmwares (BIOS) - Configuré au boot (SMRAM) - Accessible via une System Management Interrupt (SMI) - … - voir [https://wiki.osdev.org/System_Management_Mode](https://wiki.osdev.org/System_Management_Mode) - VMX (Mode virtualisé) - Gestion de la virtualisation matérielle - 2 modes d’exécution - vm-root - vmx-nonroot - … - voir [https://wiki.osdev.org/VMX](https://wiki.osdev.org/VMX) - Mode Protégé - [https://wiki.osdev.org/Protected_Mode](https://wiki.osdev.org/Protected_Mode) - segmentation - pagination - niveau de privilèges ## La segmentation du mode protégé Espace mémoire en 32 bits - Espace linéaire de 32 bits ⇒ $2^{32}$ = 4GB - pendant un temps supérieur à la RAM installée - Segmentation possible de cet espace - Adressage **relatif** au début d’un segment (adresse logique) voir [Lecture 4](https://pdos.csail.mit.edu/6.828/2005/lec/l4.html) Registres de table de descripteur de segments `gdtr`, `idtr`, `ldtr` Descripteur de segment : - Base / Limite - Type de segment - Code (X, RX), Data (R, W, RW) - Système : TSS, Task Gate, Interrupt Gate, Call Gate - gestion des modes et interruptions - D'autres informations - Chaque descripteur définit : Notions de table de descripteurs: ([https://wiki.osdev.org/Global_Descriptor_Table](https://wiki.osdev.org/Global_Descriptor_Table) / [https://wiki.osdev.org/Local_Descriptor_Table](https://wiki.osdev.org/Local_Descriptor_Table)), adresse stockée dans le registre GDTR. Sélecteurs de segments : [https://wiki.osdev.org/Segment_Selector](https://wiki.osdev.org/Segment_Selector) - seront utilisé par les registres de segments - Permettent l’accès à un descripteur - Définit : - un niveau de privilège - une table (locale ou globale) - un indice de descripteur dans cette table ![](https://notes.ar-lacroix.fr/uploads/e379aab7-0f67-4e81-a95d-64d1af969fd8.png) ### mise à jour des sélecteurs - DS, SS, ES, FS, GS : `mov <valeur> <selecteur>` - CS : Interdit de `mov` on va donc jump `ljmp <valeur>:<selecteur>` Exemple de far jump ([https://wiki.osdev.org/Segmentation#Far_Jump](https://wiki.osdev.org/Segmentation#Far_Jump)) `ljmp cs:@` - Encodage x86, permet de faire un saut long - Donne le sélecteur et l’offset - Le sélecteur est chargé dans `cs` et l’offset dans `eip` ### 2 modèles de segmentation - Le modèle "Multi-segments" : chaque segment est séparé ![](https://notes.ar-lacroix.fr/uploads/c929b24b-5131-4ca9-92b3-30bb531bc4c6.png) - le modèle "flat" : tous les selecteurs pointent sur le même descripteur ![](https://notes.ar-lacroix.fr/uploads/f69dedc6-cdd7-4b81-a5a2-e1c4b32a38c1.png) ## **Les différents niveaux de privilèges** 4 niveaux de rings qui tiennent sur 2 bits : de 0 à 3 ![](https://notes.ar-lacroix.fr/uploads/fefc9b9b-8fda-4b3a-807b-ae90c9454766.png) ### Les rings - Mode réel n’avait qu’un seul niveau (ring 0) - Mode protégé introduit des anneaux (ring level) (segmentation des privilèges) - permet d’isoler des composants logiciels de niveau - de confidentialité différents - d’intégrité différents Identificateurs de niveaux de privilèges: - **CPL** (Current Privilege Level) - niveau de privilège dans lequel on est en train de travailler - contenu dans `cs` - **RPL** (Requestor Privilege Level) - stock ce que l’utilisateur peut avoir comme privilège au niveau du descripteur - possibilité de demander un niveau de privilège - **DPL** (Descriptor Privilege Level) - stock ce que l’utilisateur peut avoir comme privilège au niveau du descripteur - [https://wiki.osdev.org/DPL](https://wiki.osdev.org/DPL) Il est potentiellement très complexe de gérer les privilèges : - Interprétation différente selon le type de segment - Transferts inter-segments (Gate) Fonctionement - On ne peut pas accéder à un segment + privilégié - on ne peut charger un descripteur qu'avec un niveau équivalent ![](https://notes.ar-lacroix.fr/uploads/6718509c-2ccc-4270-b4bf-fb303dcc3e0c.png) :::info Comparé à la pagination la segmentation est moins utile donc les OS moderne sont en Flat mais utilisent les privilèges de la segmentation. ::: ## Les interruptions et les exceptions **Intérêt des interruptions:** - Eviter l’attente active et bloquer le CPU - Déclenchement asynchrone - Apporte une composante événementielle à l’OS - Indispensable pour les périphériques d’E/S - Pouvoir être réveillé à la demande - appui sur une touche clavier - arrivée d’un paquet réseau ![](https://notes.ar-lacroix.fr/uploads/26fa14cb-1b65-4d9a-9f87-dc4fc2ab6dfc.png) Contrairement à un `jump` qui te permet de te déplacer dans ton propre espace d’adressage (au sein du même processus) `int` permet de rendre la main et un autre processus pourra potentiellement bénéficier du temps d’exécution Les **exceptions** sont des interruption, elles peuvent être générées par le CPU en cas d’erreurs (#GP, #NP, #PF) ou bien par du code (#BP) <!-- Fin Anki--> - différents types - fault ⇒ On gère et on ré-exécute l’instruction - trap ⇒ on la gère et on continue après l’instruction - abort ⇒ non récupérable - Sources des interruptions : - Périphériques => IRQ - par du code (`int 0x80` ⇒ Appel système sur un système x86) - par le CPU (exception) => Exeption - différentes natures - **irq ⇒ Périphériques** - **smi ⇒ mode SMM** - **nmi ⇒ périphériques liés à l’ACPI (**[https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface](https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface)) - **ipi ⇒ entre coeurs d’un CPU** - sert à la synchronisation en environnement SMP Infos sur les interruptions - certaines peuvent être masquées (via l’interruption `cli`) - une fois masquées, le CPU est in-interruptible - sauf dans le cas des `nmi` (Non Maskable Interrupt) La doc Intel est très très bien → *à lire le soir avant de dormir* ![](https://notes.ar-lacroix.fr/uploads/ae5805e1-5860-4915-a8e6-438fede96189.png) Pour chaque int, on peut trouver une page entiere dans le man intel qui decrit ce qu'il se passe ![](https://notes.ar-lacroix.fr/uploads/3228b183-01ef-425b-ae76-c58ecb379911.png) :::info **Note Rigolote:** Si on a une faute lors d'une exception on raise une #DF Si la #DF raise un faute, on fait donc une triple fault et le systeme reboot ![](https://notes.ar-lacroix.fr/uploads/105ee7e3-8f77-4d9c-a3dd-323f6851e786.png) ::: ### General Protection Fault : **#GP** - survient lors : - d’erreurs liées à la segmentation (taille, droits, pvl) - configuration invalide des registres de controle, MSRs - du type `fault` - fournit un code d’erreur ### Break Point: #BP - survient lorsque l’instruction int3 est exécutée - du type `trap` - pas de code d’erreur ### Invalid Opcode : #UD - survient lorsqu’une instruction est invalide - du type `fault` ### Divide Error : #DE - survient lorsque l’on effectue une division par zéro - du type `fault` ### page fault : #PF - Erreurs liées à la pagination - page non présente (pte.p/pde.p = 0) - accès read/write - accès user/supervisor On utilise les registres `cr` pour stocker les informations relatives aux interruptions pour garder cette information le plus longtemps possible le temps de pouvoir la gérer (`rd`, `ra`, etc. sont utilisés et modifiés trop fréquemment pour ça) le registre `cr2` contient l’**adresse fautive** **Traitement d'une interruption** - Registre `idtr` (propre au CPU) donne adresse du début de l’IDT (interruption description table) qui assigne à chaque interruption un handler - Le CPU stocke dans la pile le contexte processeur pour le sauvegarder : TSS (Task State Segment). - Au début d'un handler on sauvegarde le contexte de la fonction appellante - Les handlers dans l’IDT sont exécutés en ring 0 (remettre le processus(?) dans un état “valide”) - Pour ret de l'interuption, `iret` (qui va pop les registres sauvgarde sur la stack puis continuer l'execution en fonction du type d'INT ie fault, trap...) ![](https://notes.ar-lacroix.fr/uploads/7c8cc3c8-1976-4158-9d02-fb4dcbb6bf0f.png) Le registre TR (dans le CPU) contient l'indice de la table dans la GDT qui pointe vers un descripteur de type task = l'endroit où est la TSS. ![](https://notes.ar-lacroix.fr/uploads/3fb3f136-a9c7-486b-bafb-d618c1457095.png) Questions : - Est-ce que mappé en mémoire virtuelle ? - Sinon, est-ce qu’en ring 0 je peux récupérer directement le contenu d’une adresse physique, sans passer par une adresse virtuelle ? `push eax` = `mov [esp] eax` et `mov esp -/+` :::info **_Simple_ Summary by man Intel:** ![](https://notes.ar-lacroix.fr/uploads/4a0488a2-cd75-4801-91ad-42548cc1805b.png) [Source - SYSTEM ARCHITECTURE OVERVIEW by Intel](https://ics.uci.edu/~aburtsev/cs5460/lectures/midterm-pdfs/intel-intro2.pdf) ::: --- ## La pagination (en mode privilégié) Permet le mapping d'adresse virtuelle à adresse physique. Un bit du registre `cr4` sert à toggle la pagination. `cr3` contient l’adresse du PGD (Page Global Directory), chaque processus a le sien - Dans le PGD, on a des PDE (Page Directory Entry) - Dans une PDE, on a l'adresse d'une Page Table qui contient des PTE (Page Table Entry) - Cette dernière PTE correspond à l’adresse d’une page de 4 kB Le PDE socke également les infos de droits sur la page (quel ring, quels droits lecture écriture, execution...) Une adresse ça correspond à **3 offsets** **Cas de la page de 4MB :** - le premier offset est le PDE dans la PGD - le reste est l'adresse sur 4 MB **Cas de la page de 4kB :** - le premier offset nous donne la PDE dans la PGD (dont l’adresse est dans `cr3`) - (`cr3` + offset = PDE) - le deuxième offset nous donne la PTE dans la PDE - (PDE + offset = PTE) - le troisième offset nous indique où dans la page 4 kB - (PTE + offset = contenu mémoire) ![](https://notes.ar-lacroix.fr/uploads/a3712b94-3ae3-419d-94a1-076015f853b2.png) ![](https://notes.ar-lacroix.fr/uploads/0dfdf6a6-4a30-4c2c-af96-41f4fd6d76fe.png) ![](https://notes.ar-lacroix.fr/uploads/0f746935-3af2-450c-9bc4-87709803ec4f.png) :::warning Pour une même adresse virtuelle on peut avoir plusieurs adresses physiques ::: #### Traduction Pour chaque adresse il faut la traduire, check les privilèges : Solution : cache du CPU **TLB → Translation Lookaside Buffer:** - Cache spécifique qui conserve la traduction adresse virt → adresse phys - Dès que `cr3` change, on flush le TLB (tout est supprimé) #### Espace réservé OS On veut réserver le dernier GB au kernel Pour permettre ça le kernel va au démarage définir un flag sur les entrées de la PGD d'adresse $\ge$ 0xc00 et les mettre en privilège ring 0. Le PGD par exemple est dans la page noyau. Chaque programme a sa propre mémoire virtuelle avec le dernier giga mappé sur une mémoire kernel (tables de pages, d'interruptions ...) #### Problème de la virtualisation Comment le kernel peut lire les tables de gestion de la mémoire si maintenant les tables sont virtuelle? Solutions : - Self mapping : - La première page est en self-map et permet de stocker les tables de pages. On la crée avant d'activer la pagination et on fait en sorte de pouvoir retomber dessus. - Autres solutions : - identity mapping - correspondance linéaire virtuelle/physique : page offset ## Le TP sécu, les points bonus et la dépression (titre non contractuel mais il est minuit j'en peux plus) :::success RÉCAP ! Sujet : ![](https://notes.ar-lacroix.fr/uploads/30583bac-ccb6-4670-8a80-d5fe4f47100d.png) ::: ## Et la sécurité dans tout ça ? - La segmentation est utilisée pour les privilèges (pas pour la ségrégation) - La pagination sert à protéger le noyau des tâches (User/supervisor) - Améliorations - différenciation des TLB (instruction/données TLB) - PAGEEXEC - protection via CR0 - Write protect : si le bit est à 0 le kernel n'a pas le droit d'écrire les pages read-only - SMEP/SMAP - SMAP : empêche ring 0 d'accéder à des pages user - SMEP : empêche ring 0 d'exec à des pages user