Vous n’avez pas vécu tant que vous n’avez pas vu un programme « parfaitement correct » de l’époque DOS imploser parce que quelqu’un a supposé que la mémoire est juste… de la mémoire. Le 80286 (le « 286 ») est le point où cette supposition a commencé à perdre sa licence. Il a introduit le mode protégé — de vraies permissions, une vraie isolation, un véritable espace d’adressage au‑delà du plafond de 1 Mo. Aussi : une série de bords tranchants qui ont forcé développeurs et opérateurs à mériter leur café.
Si vous exploitez des systèmes en production aujourd’hui, l’histoire du 286 reste pertinente. Le mode protégé est l’ancêtre du contrat de base sur lequel on compte : l’espace utilisateur ne peut pas écrire sur la mémoire du noyau, les processus ne se piétinent pas entre eux, et le système d’exploitation peut faire respecter des règles. Le 286 a livré ce contrat tôt, imparfaitement, et avec une “fonctionnalité” notoire qui a façonné une décennie de logiciels PC : sur le 286, entrer en mode protégé était facile ; revenir de façon fiable au mode réel ne l’était pas.
Ce que le 286 a changé (et pourquoi ça intéressait quelqu’un)
L’Intel 80286 (1982) est souvent rappelé comme « le CPU du IBM PC/AT ». C’est vrai, mais cela minimise le changement. Le 286 est l’endroit où la lignée x86 a commencé à se comporter comme si elle voulait être un vrai système multi‑utilisateurs, multitâche. Pas une machine de loisir qui exécutait un programme à la fois et lui donnait les clés de la ville.
Le mode protégé sur le 286 a introduit des mécanismes matériels que les opérations modernes tiennent pour acquis :
- Protection mémoire : on peut marquer des segments mémoire avec des permissions d’accès. Fini le « oups j’ai écrit dans le noyau ».
- Niveaux de privilège : privilèges en anneaux et transitions contrôlées via des gates. Le noyau peut rester noyau.
- Échafaudage de mémoire virtuelle : pas de pagination encore (c’est l’ère du 386), mais le cadre conceptuel : traduction d’adresses via des tables, limites, privilèges.
- Un espace d’adressage plus grand : adressage physique au‑delà de 1 Mo, jusqu’à 16 Mo.
Mais il est aussi arrivé avec des contraintes qui, pour l’écosystème PC du milieu des années 80, équivalaient à construire un métro avant les gares. La plupart des utilisateurs tournaient encore sous DOS, qui était lié au mode réel. Les développeurs écrivaient pour DOS parce que c’est là que se trouvaient les clients. Et le mode protégé sur le 286 comportait une trappe : une fois entré, revenir au mode réel est… gênant.
Ce décalage — capacité matérielle contre réalité logicielle — est le cœur de l’histoire du 286. C’est aussi un thème récurrent en ingénierie de production : un changement de plateforme promet sécurité et performance, mais la voie de migration est là où naît le temps d’arrêt.
Mode réel : le studio exigu où tout le monde refusait d’emménager
Pour comprendre pourquoi le mode protégé du 286 « torturait les développeurs », il faut partir de la base : le mode réel 8086/8088. Le mode réel n’est pas « mauvais » en soi. Il est minimal. Il est simple. Il démarre facilement. C’est le mode dans lequel le CPU commence quand on l’allume, et le firmware s’y attend.
En mode réel :
- Les adresses se forment en segment:offset, avec
physical = segment * 16 + offset. - On peut adresser 1 Mo de mémoire (espace d’adressage 20 bits).
- Il n’y a pas de séparation forcée entre OS et applications. N’importe quel code peut écrire n’importe où.
- Les interruptions et les services BIOS sont conçus pour ce modèle.
DOS s’est appuyé sur le mode réel parce que DOS était, à l’origine, un environnement mono‑tâche pour petites machines. Il externalisait l’abstraction matériel vers les appels BIOS, lançait des programmes qui se croyaient seuls, et comptait sur le « ne faites pas ça » plutôt que sur le « vous ne pouvez pas faire ça ».
La segmentation en mode réel est aussi une sorte de pouvoir étrange : elle vous permet de « déplacer » la même fenêtre d’offset dans la mémoire en changeant le registre de segment. Les gens ont construit des modèles mémoire astucieux, des overlays, des astuces EMS, et du code qui traitait la segmentation comme une fonctionnalité. Puis le mode protégé est arrivé et a dit : « La segmentation est toujours là, mais maintenant c’est sérieux. »
Blague #1 : Le mode réel, c’est comme exécuter la production en root parce que « c’est plus rapide ». C’est plus rapide, jusqu’au moment où ça ne l’est plus.
Mode protégé sur 286 : la segmentation qui devient sérieuse
Le mode protégé sur le 286 conserve l’idée de segmentation mais remplace le calcul d’adresse « segment * 16 » par un système piloté par tables. Au lieu qu’un registre de segment contienne une adresse de base (à peu près), il contient un sélecteur qui indexe un descripteur. Ce descripteur indique au CPU :
- la base de l’adresse du segment
- la limite (sa taille)
- le type (code/données/système)
- le niveau de privilège (qui peut y accéder)
- bits de présence/validité et d’autres champs de contrôle
GDT, LDT, et pourquoi les tables deviennent votre vie
Le 286 a introduit des tables de descripteurs :
- GDT (Global Descriptor Table) : descripteurs globaux système.
- LDT (Local Descriptor Table) : descripteurs par tâche (ou par processus).
- IDT (Interrupt Descriptor Table) : comment interruptions et exceptions transfèrent le contrôle en toute sécurité.
En termes opérationnels : le 286 a transformé le mapping mémoire en configuration. Vous ne « consommez » plus seulement de la mémoire ; vous la définissez. Une mauvaise définition ne rend pas un comportement « un peu erroné ». Elle provoque des exceptions.
Anneaux de privilège et transitions contrôlées
Le mode protégé inclut des niveaux de privilège (anneaux). Le 286 prend en charge les anneaux 0–3. L’anneau 0 est destiné au noyau. L’anneau 3 est pour les applications. Les gates (call gates, interrupt gates, task gates) permettent d’entrer de façon contrôlée dans du code de privilège supérieur.
Cette machinerie est ce qui rend le concept de « multi‑utilisateur » crédible. Un plantage en espace utilisateur ne devrait pas faire tomber toute la machine. Mais cela signifie aussi que les développeurs ne peuvent plus tricher aussi facilement. Certaines des « optimisations » les plus courantes de l’époque DOS étaient essentiellement des triches : accès direct au matériel, écrasement de vecteurs d’interruption, tripotage des structures BIOS. En mode protégé, cela devient illégal sauf si l’OS l’autorise explicitement.
Espace d’adressage : plus grand, mais pas comme vous le vouliez
Le 286 peut adresser jusqu’à 16 Mo de mémoire physique en mode protégé (24 bits). C’est un saut important depuis 1 Mo. Mais le 286 reste fondamentalement segmenté. Il n’y a pas de pagination. Vous n’obtenez pas un espace linéaire plat, paginé à la demande. Vous obtenez de la segmentation avec des limites.
C’est là que les développeurs se sont retrouvés coincés : ils voulaient plus de mémoire et rester compatibles avec les attentes DOS + BIOS. Le 286 leur a donné plus de mémoire et un nouvel ensemble de règles, mais il ne leur a pas donné un mode hybride facile à utiliser. Ce tour devient plus simple avec le 386.
Le problème du « pas de retour au mode réel » : un bit, beaucoup de maux de tête
Voici le centre de l’affaire : sur le 286, une fois que vous réglez le bit PE (Protection Enable) dans CR0 pour entrer en mode protégé, il n’existe pas de séquence d’instructions architecturale propre pour le nettoyer et revenir au mode réel. La méthode officielle d’Intel était, en pratique : réinitialiser le CPU.
Oui, réinitialiser. Comme dans, ramener le processeur à son état de démarrage. Ce n’est pas la façon d’écrire un programme DOS fluide qui veut utiliser brièvement la mémoire en mode protégé puis appeler des interruptions BIOS.
Il y avait des contournements, et ce sont le genre de contournements qui donnent des tics aux SRE :
- Réinitialisation par triple fault : provoquer intentionnellement une cascade de fautes qui réinitialise le CPU. Rapide, brutal.
- Réinitialisation via le contrôleur clavier (8042) : basculer la ligne reset du CPU via le contrôleur clavier. Tout aussi brutal, et votre état CPU est perdu.
- Astuces BIOS/firmware : certaines machines offraient des chemins spécifiques au fournisseur. La fiabilité variait selon la machine et la révision du BIOS.
Le mode protégé était l’avenir, mais DOS et les services BIOS étaient le présent. Cela faisait du 286 un CPU de transition avec un workflow très peu transitionnel. Vous pouviez construire des OS pour lui (et des gens l’ont fait), mais vous ne pouviez pas facilement construire des couches de compatibilité DOS qui sautaient dans et hors du mode protégé sans violer l’état de la machine.
C’est la partie qui a « torturé les développeurs » : ce n’était pas seulement différent ; cela cassait des hypothèses sur le flux de contrôle. L’OS voulait posséder la machine ; les applis DOS voulaient posséder la machine. Le 286 a rendu l’une de ces parties mécontente.
La porte A20 : l’interrupteur le plus étrange de l’histoire du PC
Si vous avez déjà entendu de vieux ingénieurs marmonner « A20 », c’est l’héritage de la compatibilité rétro qui a mangé la conception matérielle.
Le 8086 avait 20 lignes d’adresse (A0–A19) pour un adressage 1 Mo. Mais à cause de la façon dont fonctionne l’arithmétique segment:offset, les adresses pouvaient se replier à 1 Mo d’une manière sur laquelle certains logiciels se reposaient par accident. Quand IBM a construit le PC/AT avec le 286, ils ont ajouté de la mémoire au‑delà de 1 Mo, et ces repliements ont cessé — cassant des logiciels.
Le compromis fut la porte A20 : un mécanisme pour forcer la ligne d’adresse A20 à 0, simulant le comportement de repli ancien. Si A20 est désactivée, les adresses au‑delà de 1 Mo se replient dans le premier mégaoctet. Si elle est activée, vous pouvez accéder correctement à la mémoire étendue.
La porte A20 était souvent contrôlée via le contrôleur clavier (le 8042), ce qui est une phrase qui sonne encore comme de la satire. Vous aviez un CPU capable du mode protégé et des mégaoctets de RAM, et vous basculiez une ligne d’adresse mémoire par le biais de la puce clavier parce que la compatibilité l’exigeait.
Opérationnellement, A20 est un piège classique du « ça marche sur ma machine » : différents chipsets et implémentations BIOS se comportaient différemment, le timing comptait, et certaines séquences étaient instables sous charge ou dans des états matériels particuliers. Quand la porte A20 se comporte mal, vous voyez des motifs de corruption mémoire qui ressemblent à des fantômes. Ce ne sont pas des fantômes. Ce sont des repliements.
Choix de conception qui ont compté sur le terrain
L’ère 286 est celle où « PC » a commencé à signifier « plateforme à usage général », pas « appareil mono‑utilisateur ». Mais les choix de conception venaient avec des compromis qui se mappent clairement aux leçons opérationnelles modernes.
La segmentation est une politique, pas juste de l’adressage
En mode protégé, la segmentation devient votre outil d’application : base, limite, privilège. Si vous configurez mal des descripteurs, vous n’obtenez pas un « comportement un peu erroné ». Vous obtenez des exceptions. C’est bien — échec rapide — mais seulement si vous pouvez le déboguer.
La compatibilité n’est pas gratuite, c’est un système
La porte A20 existe parce que des logiciels dépendaient d’un comportement indéfini. Ce n’est pas une faute morale ; c’est ce qui arrive quand une plateforme devient populaire. Si vous livrez une fonction de compatibilité, vous livrez aussi le coût opérationnel de cette fonction pour des années.
Les transitions d’état sont l’endroit où la fiabilité meurt
L’incapacité à revenir proprement au mode réel a forcé les développeurs à construire des transitions basées sur des réinitialisations. Les transitions basées sur la réinitialisation signifient perte d’état. La perte d’état implique qu’il faut sauvegarder/restaurer soigneusement, des initialisations idempotentes et une programmation défensive. En d’autres termes : le 286 a forcé la « pensée fiabilité » dans des logiciels culturellement pas prêts.
Une citation à garder dans votre poche
« L’espoir n’est pas une stratégie. » — General Gordon R. Sullivan
Si vous avez déjà tenté de « basculer en mode protégé juste une seconde » sur un 286, vous avez appris cela à la dure.
Faits intéressants et contexte historique (points rapides)
- Sortie 1982 : Le 80286 est arrivé en 1982 et a propulsé le IBM PC/AT, le consacrant comme CPU « business PC ».
- Adressage physique 16 Mo : En mode protégé, le 286 pouvait adresser jusqu’à 16 Mo (24 bits), un saut massif par rapport au 8086 et son 1 Mo.
- Pas de pagination : Le 286 disposait d’une protection basée sur la segmentation mais pas de pagination ; l’histoire moderne de mémoire virtuelle plate devient pratique avec le 80386.
- Pression de compatibilité mode réel : DOS et l’écosystème BIOS ont forcé le matériel à préserver des comportements comme le repli à 1 Mo, motivant la porte A20.
- OS/2 comme cible initiale : IBM et Microsoft visaient initialement OS/2 sur des machines de classe 286 ; la transition vers la pensée 386 est survenue à mesure que la pagination et la compatibilité devenaient évidentes.
- Retour propre manquant : Le chemin d’activation du mode protégé du 286 n’était pas assorti d’un chemin de désactivation propre ; retourner au mode réel demandait généralement une séquence de reset.
- Les tables de descripteurs furent une grande avancée : GDT/LDT/IDT ont introduit une architecture plus centrée OS, poussant les PC vers des modèles proches des stations de travail.
- Contrôle A20 via 8042 : Beaucoup de systèmes AT basculaient A20 via le contrôleur clavier, créant des bizarreries de timing et de fiabilité qui résonnent encore dans les bootloaders.
- Le mode protégé 286 n’était pas « optionnel » pour les vrais OS : si vous vouliez protection mémoire et multitâche, le mode protégé était la voie — même si le reste du monde logiciel PC n’était pas prêt.
Trois mini‑histoires du monde de l’entreprise
Mini‑histoire 1 : L’incident provoqué par une mauvaise hypothèse
Une société de services financiers a hérité d’une application métier « modernisée » en phases : d’abord pour des CPU plus rapides, ensuite pour plus de mémoire. La cible de déploiement était une flotte de machines AT dans des agences, encore fortement centrées DOS pour compatibilité avec des périphériques et des outils fournisseurs.
Un développeur a supposé que l’API du gestionnaire de mémoire « mémoire étendue » impliquait un accès plat au‑dessus de 1 Mo. Ils ont écrit un gestionnaire de tampons qui copiait des enregistrements de longueur variable dans ce qu’ils croyaient être une région contiguë, puis ont stocké des pointeurs lointains comme si l’arithmétique des segments se comportait de la même façon selon les modes.
Pendant le pilote tout fonctionnait. En production, le système a commencé à produire une corruption de données intermittente après plusieurs heures. Pas des crashs — pire. La base de données passait des vérifications superficielles, mais certains enregistrements revenaient avec des champs brouillés. Le personnel des agences accusait le réseau. L’équipe réseau accusait les « vieux PC ». Tout le monde avait techniquement raison et opérationnellement inutile.
La cause racine était une hypothèse de frontière de mode : une partie du code s’exécutait avec A20 désactivée pendant certaines routines assistées par le BIOS. Les écritures du gestionnaire de tampons « au‑dessus de 1 Mo » se repliaient dans le premier mégaoctet et atterrissaient parfois sur des structures rarement touchées — d’où l’apparence aléatoire de la corruption.
La correction n’était pas glamour : imposer l’état d’A20 avant d’accéder à la mémoire étendue, ajouter des motifs de garde et des validations aux limites des enregistrements, et cesser de stocker des pointeurs dépendant de mises en page de segment transitoires. La leçon réelle était culturelle : si votre correction dépend d’un verrou matériel qui doit être dans une certaine position, vous n’avez pas la correction — vous avez une superstition.
Mini‑histoire 2 : L’optimisation qui s’est retournée contre eux
Une usine voulait une UI plus rapide sur ses terminaux de plancher. L’appli était DOS‑based avec du graphique personnalisé, et le vendeur proposait une version « mode accéléré » qui utilisait le mode protégé pour le blitting et la décompression. Le pitch commercial était simple : « plus de mémoire, plus grand cache, moins de lectures disque ».
En laboratoire c’était génial. Sur la chaîne c’était le chaos. Les terminaux se figeaient occasionnellement pendant quelques secondes, puis reprenaient. Parfois un terminal redémarrait en plein service. Les opérateurs ont appris à sauvegarder constamment, ce qui est un anti‑pattern mesurable dans les taux d’ulcères.
L’ingénierie a tracé le problème jusqu’au contournement de retour en mode réel. La build accélérée entrait en mode protégé, faisait le travail, puis forçait un chemin de reset pour revenir aux routines DOS/BIOS pour l’I/O des périphériques. La réinitialisation était « douce » mais remettait quand même assez d’état pour que des périphériques nécessitent une réinitialisation. La plupart du temps l’appli récupérait. Parfois non, et le terminal redémarrait.
L’optimisation était réelle — jusqu’à ce qu’elle touche les bords du système : périphériques, appels BIOS et timing. Ils ont annulé la build accélérée et ont implémenté un cache en mémoire conventionnelle plus ennuyeux mais fiable, et des accès disque plus intelligents. C’était plus lent sur les benchmarks mais plus rapide sur le seul benchmark qui compte : la disponibilité pendant un shift.
Mini‑histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une compagnie d’assurances faisait tourner un système multi‑utilisateur précoce sur des machines de classe 286 avec une couche OS en mode protégé. Leur environnement était un patchwork : certains sites avaient des machines récentes, d’autres bloquées par des cycles d’achats. L’équipe plateforme avait une règle qui paraissait douloureusement conservatrice : chaque déploiement inclut une suite de tests de validation de mode.
La suite n’était pas sophistiquée. Elle vérifiait la configuration des tables de descripteurs, les transitions de privilège et le comportement d’A20 sous bascules répétées. Elle consignait les échecs et refusait d’avancer si la machine déviait du comportement matériel attendu. Certaines équipes se plaignaient que cela ralentissait les déploiements. Elles avaient tort, mais avec volume.
Un trimestre, le service des achats a sourcé un lot de cartes mères « compatibles ». Elles bootent DOS correctement. Elles exécutent même la plupart des applis. Mais sous stress mode protégé, le basculement d’A20 était incohérent à cause d’un bug de chipset. Sans la suite de validation, l’OS aurait été déployé et les pannes seraient apparues comme des « crashs aléatoires » des semaines plus tard.
Au lieu de cela, la suite a échoué immédiatement en staging. Le fournisseur a dû remplacer les cartes. La pratique ennuyeuse — tester les invariants, à chaque fois — a évité un incident en queue longue qui aurait consommé des mois de blâme et des week‑ends de travail.
Tâches pratiques : commandes, sorties et la décision que vous prenez
Vous ne pouvez pas SSH dans un 286 en 2026 (du moins pas légalement), mais vous pouvez diagnostiquer des problèmes liés aux modes dans des émulateurs, des environnements de boot et des systèmes modernes où des transitions mode réel/mode protégé existent encore durant le démarrage. Les tâches ci‑dessous sont pratiques pour :
- déboguer des bootloaders et la mise en route précoce d’un noyau
- reproduire un comportement d’époque 286 en émulation
- valider le comportement A20 et les maps mémoire
- comprendre des hypothèses segmentation/mode protégé qui fuient encore dans le code firmware
Task 1: Confirm CPU mode transitions during boot with QEMU + debug logs
cr0x@server:~$ qemu-system-i386 -M pc -cpu 286 -m 16M -drive file=disk.img,format=raw -d int,cpu_reset -no-reboot
...QEMU 8.x...
CPU Reset (CPU 0)
...INT: vector=0x10 ...
...
Ce que ça signifie : Vous exécutez un émulateur i386 configuré avec un modèle CPU compatible 286. Les flags de debug montrent les resets et les interruptions.
Décision : Si votre séquence de boot repose sur le retour au mode réel sans événement de reset, vous construisez sur du sable. Prévoyez une transition basée sur reset ou redesign pour éviter les appels BIOS après le mode protégé.
Task 2: Inspect the guest’s memory map from the host (QEMU monitor)
cr0x@server:~$ (echo "info mtree"; sleep 1) | socat - UNIX-CONNECT:/tmp/qemu-monitor.sock
memory
0000000000000000-000000000009ffff (prio 0, i/o): ram
00000000000f0000-00000000000fffff (prio 0, i/o): rom
0000000000100000-0000000000ffffff (prio 0, i/o): ram
Ce que ça signifie : La basse mémoire, la région ROM et la RAM au‑dessus de 1 Mo sont mappées. Votre « mémoire étendue » existe.
Décision : Si la mémoire étendue n’est pas présente ou est mappée de façon étrange, ne déboguez pas le mode protégé encore — corrigez d’abord la configuration de la plateforme.
Task 3: Detect whether A20 is enabled in a Linux boot environment
cr0x@server:~$ dmesg | grep -i a20 | head
[ 0.000000] BIOS-provided physical RAM map:
[ 0.000000] ...
Ce que ça signifie : Les noyaux modernes n’impriment souvent pas « A20 enabled », mais l’absence de lignes explicites signifie que vous avez besoin d’autres preuves.
Décision : Si vous déboguez un stage de bootloader/firmware, ne fiez pas aux logs du noyau comme preuve. Validez A20 plus tôt (dans votre code de boot ou via l’instrumentation de l’émulateur).
Task 4: Identify whether you are in a VM/emulator that might mask A20 issues
cr0x@server:~$ systemd-detect-virt
kvm
Ce que ça signifie : Vous êtes virtualisé ; les bizarreries bas niveau peuvent être abstraites ou implémentées « trop correctement ».
Décision : Si le bug n’apparaît que sur hardware physique (ou seulement dans un émulateur), traitez A20 et les chemins de reset comme suspects. Reproduisez sur au moins deux environnements.
Task 5: Confirm the CPU flags and architecture details (useful when testing 286-like constraints)
cr0x@server:~$ lscpu | sed -n '1,12p'
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Vendor ID: GenuineIntel
Model name: Intel(R) Xeon(R) CPU
CPU family: 6
Model: 85
Stepping: 7
Ce que ça signifie : Vous n’êtes pas sur un 286, évidemment. Mais vous confirmez que vous avez besoin d’émulation pour tester des comportements 286.
Décision : Si quelqu’un propose « testez sur un PC de rechange », arrêtez‑le. Les bugs de transition de mode dépendent du timing et de la plateforme. Utilisez une émulation déterministe plus au moins une cible réelle.
Task 6: Validate that your boot image actually contains a protected-mode capable loader
cr0x@server:~$ file bootloader.bin
bootloader.bin: DOS/MBR boot sector
Ce que ça signifie : C’est un secteur de boot, probablement 16‑bit. Pas la preuve qu’il n’entre jamais en mode protégé, mais un indice.
Décision : Si vous attendez des fonctionnalités du mode protégé (setup de descripteurs, usage mémoire étendue), assurez‑vous que votre loader a l’étape suivante nécessaire. Ne chassez pas des bugs de mode dans un stage incapable de faire le travail.
Task 7: Disassemble boot code to spot protected-mode enable sequences
cr0x@server:~$ ndisasm -b 16 bootloader.bin | grep -E "lgdt|lidt|mov cr0|smsw|lmsw" | head
0000003A 0F0116 lgdt [0x1601]
00000040 0F20C0 mov eax,cr0
00000043 6683C801 or eax,byte +0x1
00000047 0F22C0 mov cr0,eax
Ce que ça signifie : Ce code met PE=1 dans CR0 via une séquence de style 386+. Sur un vrai 286 vous verriez plus couramment l’usage de lmsw ; les émulateurs peuvent accepter plus.
Décision : Si vous ciblez vraiment 286, assurez‑vous que le jeu d’instructions correspond. Un nombre surprenant de loaders « 286 » supposent silencieusement des instructions 386.
Task 8: Confirm GDT presence and sanity in a kernel image (rough heuristic)
cr0x@server:~$ strings -a kernel.bin | grep -i -E "gdt|ldt|idt" | head
GDT
IDT
Ce que ça signifie : Faible preuve : les symboles/chaînes peuvent induire en erreur, mais cela suggère que l’image contient une logique de setup du mode protégé.
Décision : Si vous ne voyez aucun indice de tables de descripteurs dans un système qui revendique le mode protégé, suspectez la configuration de build ou un artefact déployé incorrect.
Task 9: Check for unexpected resets that may be the “return to real mode” hack
cr0x@server:~$ qemu-system-i386 -M pc -cpu 286 -m 16M -drive file=disk.img,format=raw -d cpu_reset -no-reboot 2>&1 | head -n 20
CPU Reset (CPU 0)
CPU Reset (CPU 0)
CPU Reset (CPU 0)
Ce que ça signifie : Plusieurs resets durant ce qui devrait être un seul chemin de boot. C’est un indice fort pour des transitions de mode basées sur reset ou une boucle de triple‑fault.
Décision : Si les resets font partie de votre conception, rendez‑les explicites et contrôlées. Si ce sont des accidents, vous avez un problème critique de handler d’exception (IDT invalide, descripteur mauvais, problèmes de pile).
Task 10: Identify triple fault behavior by correlating “no output” with reset loops
cr0x@server:~$ qemu-system-i386 -M pc -cpu 286 -m 16M -drive file=disk.img,format=raw -d int,cpu_reset -no-reboot 2>&1 | sed -n '1,40p'
CPU Reset (CPU 0)
...INT: vector=0x0d ...
CPU Reset (CPU 0)
...INT: vector=0x08 ...
CPU Reset (CPU 0)
Ce que ça signifie : Vous voyez des exceptions (comme #GP, vector 0x0d) suivies de resets. C’est cohérent avec une faute qui ne peut pas être gérée parce que le chemin du handler faut aussi.
Décision : Arrêtez d’optimiser. Construisez un IDT minimal avec des handlers connus bons avant de faire quoi que ce soit de sophistiqué. Votre premier job : « ne pas réinitialiser de façon inattendue ».
Task 11: Validate that your build targets 16-bit/286 constraints (no accidental 386 opcodes)
cr0x@server:~$ objdump -D -b binary -m i8086 bootloader.bin | head -n 20
bootloader.bin: file format binary
Disassembly of section .data:
00000000 <.data>:
0: fa cli
1: 31 c0 xor %ax,%ax
3: 8e d8 mov %ax,%ds
Ce que ça signifie : Vous utilisez une vue disassembleur 8086. Si vous voyez des non-sens, c’est peut‑être parce que le code n’est pas pur 16‑bit ou contient des encodages 386+.
Décision : Si la désassemblage n’a pas de sens, confirmez vos paramètres d’assembleur et la CPU cible. Un bootloader « qui marche dans l’émulateur » mais qui utilise les mauvaises instructions est un incident futur à retardement.
Task 12: Detect boot-time memory region conflicts that mimic “protected mode bugs”
cr0x@server:~$ dmesg | grep -E "BIOS-e820|reserved|System RAM" | head -n 15
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000003fffffff] usable
Ce que ça signifie : Le firmware marque certaines régions de basse mémoire comme réservées. Sur de vieux systèmes ces régions sont sacrées : zones de données BIOS, ROM, fenêtres mémoire des périphériques.
Décision : Si votre code mode protégé place tables/stacks dans la basse mémoire réservée, vous verrez des fautes et des corruptions « aléatoires ». Déplacez les structures critiques vers des régions sûres et documentez la mise en page.
Task 13: Confirm that your init path isn’t accidentally calling BIOS interrupts after switching modes
cr0x@server:~$ ndisasm -b 16 stage2.bin | grep -n "cd 10" | head
412:00000334 CD10 int 0x10
Ce que ça signifie : int 0x10 est une interruption vidéo BIOS conçue pour le mode réel. Si cette instruction est atteignable après PE=1, vous flirtez avec le désastre.
Décision : Soit effectuez le travail BIOS avant le switch, soit implémentez une stratégie de virtual 8086 / thunking (pas sur 286), soit écrivez des drivers natifs. Ne faites pas « juste un essai ».
Task 14: Use emulator logging to verify descriptor loads
cr0x@server:~$ qemu-system-i386 -M pc -cpu 286 -m 16M -drive file=disk.img,format=raw -d cpu -no-reboot 2>&1 | grep -E "LGDT|LLDT|LIDT" | head
LGDT base=00008f00 limit=0037
LIDT base=00009000 limit=03ff
Ce que ça signifie : L’émulateur affiche des chargements des registres de tables de descripteurs avec des valeurs base/limit.
Décision : Si bases/limits pointent vers des régions suspectes (comme la ROM ou sous votre bootloader), arrêtez et corrigez la mise en page. Les tables de descripteurs doivent résider en RAM stable qui ne sera pas écrasée.
Blague #2 : Déboguer le mode protégé sans un IDT connu bon, c’est comme déployer un vendredi sans rollback. Vous pouvez le faire, mais vous ne devriez pas.
Roue de diagnostic rapide : trouver le goulot vite
Voici le « quoi vérifier d’abord quand tout brûle ». Utilisez‑le quand un chemin de boot de type 286 se bloque, réinitialise, corrompt la mémoire ou se comporte différemment selon les machines/émulateurs.
Premier : prouvez dans quel mode vous êtes réellement
- Vérifiez la séquence d’activation du mode protégé dans votre code de boot (cherchez
lmswou manipulation de CR0 et un far jump). - Corrélez avec les logs de l’émulateur pour resets et exceptions. Les resets inattendus signifient souvent des triple faults.
Résultat : Si vous n’entrez pas en mode protégé, arrêtez de diagnostiquer des problèmes de mode protégé. Réparez le flux de contrôle.
Deuxième : validez les tables de descripteurs avant de faire quoi que ce soit
- Confirmez que la base/limit de la GDT pointent vers de la RAM valide et ne sont pas écrasées plus tard.
- Assurez‑vous que les descripteurs code et données ont des bases/limits sensés et des bits de privilège corrects.
- Mettez en place un IDT minimal avec un handler qui halt/logge.
Résultat : Si les fautes deviennent « gérées », vous avez transformé le chaos en un système débogable.
Troisième : traitez A20 comme une dépendance dure, pas facultative
- Rendez l’activation d’A20 explicite et vérifiez‑la (dans votre code ou via des motifs de test connus).
- Ne mélangez pas logique « A20 peut être activée » avec des écritures en mémoire étendue. C’est comme ça qu’on obtient une corruption silencieuse.
Résultat : Si la corruption disparaît quand A20 est forcée, votre bug est lié à la compatibilité, pas « aléatoire ».
Quatrième : éliminez les appels BIOS après le switch
- Auditez la présence de
int 0x10,int 0x13, etc. après l’entrée en mode protégé. - Soit effectuez le travail BIOS avant le switch, soit écrivez des drivers natifs.
Résultat : Si vous arrêtez d’appeler le BIOS dans le mauvais mode, les blocages disparaissent et la fiabilité revient.
Cinquième : décidez si les resets sont conception ou défaut
- Si vous dépendez du reset pour revenir au mode réel, implémentez sauvegarde/restauration d’état et rendez le chemin reset déterministe.
- Si vous n’en dépendez pas, traitez tout reset comme un défaut critique et corrigez la gestion d’exceptions.
Erreurs courantes : symptôme → cause racine → correction
1) Symptôme : corruption de données aléatoire après usage de « mémoire étendue »
Cause racine : Porte A20 désactivée ou basculante de façon non fiable ; les adresses au‑dessus de 1 Mo se replient dans la basse mémoire.
Correction : Rendre l’activation d’A20 explicite ; vérifier avec un test d’alias mémoire ; éviter les appels BIOS ou chemins de code qui changent implicitement l’état d’A20.
2) Symptôme : reboot immédiat après passage en mode protégé
Cause racine : Triple fault due à un IDT invalide, un descripteur mauvais, ou la pile non réglée correctement pour le nouveau mode.
Correction : Charger un IDT minimal avant d’activer PE ; s’assurer que les segments code/données sont valides ; régler SS:SP sur une pile protégée sûre ; tester avec les logs d’exception de l’émulateur.
3) Symptôme : marche dans l’émulateur, échoue sur hardware spécifique
Cause racine : L’émulateur est plus déterministe ou implémente A20/reset différemment ; le hardware réel a des contraintes de timing et des quirks de chipset.
Correction : Ajouter des delays/polling où nécessaire (surtout pour A20 via 8042) ; tester sur au moins une cible physique représentative ; éviter de compter sur un timing non défini.
4) Symptôme : le code en mode protégé s’exécute mais les services BIOS bloquent
Cause racine : Appels d’interruptions BIOS depuis le mode protégé sur un 286 sans proper thunking (limité sur 286).
Correction : Faire les appels BIOS en mode réel avant le switch ; ou garder un stub en mode réel et transiter via un reset contrôlé ; mieux encore, écrire des routines natives.
5) Symptôme : fautes de limite étranges en accédant à des buffers « dans les limites »
Cause racine : Limite de segment mal configurée (descripteur trop petit) ou mauvais sélecteur utilisé après un far call/return.
Correction : Définir descripteurs avec base/limit corrects ; centraliser définitions de sélecteurs ; ajouter des asserts en builds debug qui valident les sélecteurs avant usage.
6) Symptôme : crash intermittent sous charge, stable en pas à pas
Cause racine : Contrôle A20 dépendant du timing via 8042, ou dépendance à une mémoire de table non initialisée qui « marche par hasard » quand on ralentit.
Correction : Poller correctement les bits de statut du contrôleur ; zero‑init la mémoire des tables ; éviter le code d’initialisation auto‑modifiant ; tester à pleine vitesse avec logging.
7) Symptôme : « optimisation » par accès direct au matériel casse sous OS en mode protégé
Cause racine : L’application attend des privilèges ring‑0 ; le mode protégé applique le privilège et bloque l’accès aux ports I/O.
Correction : Déplacer l’accès matériel dans un driver/service en ring 0 ; exposer une API stable ; ne pas livrer d’apps qui dépendent d’un privilège indéfini.
Checklists / plan pas à pas
Checklist : faire monter le mode protégé en toute sécurité (à la sauce 286)
- Verrouiller la mise en page mémoire : décider où résident GDT/IDT/pile ; éviter les regions basses réservées.
- Construire un GDT minimal : descripteur null + segment code + segment données.
- Construire un IDT minimal : handler pour fautes communes qui halt/logge ; faites‑le avant d’activer PE.
- Activer A20 explicitement : ne supposez pas que le BIOS l’a laissée activée.
- Passer en mode protégé : régler PE et faire le far jump requis pour vider le prefetch et charger CS correctement.
- Recharger les registres de segment : DS/ES/SS avec des sélecteurs valides ; définir une pile sûre.
- Ne faites qu’une chose à la fois : écrire sur un port debug, basculer un pin I/O connu, ou écrire un motif mémoire connu. Confirmer la stabilité.
- Puis ajoutez la complexité : task switching, usage LDT, séparation des privilèges.
Checklist : décider de garder la compatibilité DOS/BIOS
- Inventoriez les dépendances d’interruptions BIOS : vidéo, disque, clavier, etc.
- Classez chaque dépendance : peut‑elle être front‑loadée avant le switch, remplacée par un driver natif, ou éliminée ?
- Choisissez une stratégie de transition :
- Si vous devez revenir au mode réel sur un 286 : concevez pour des transitions basées sur reset et une réinitialisation d’état.
- Si vous contrôlez tout l’OS : restez en mode protégé ; évitez le BIOS après le boot.
- Testez le comportement A20 sous stress : cycles répétés d’activation/désactivation si votre conception y touche.
- Consignez les invariants : « A20 doit être activée avant les écritures en mémoire étendue » n’est pas une trivia ; c’est un SLO.
Pas à pas : triage d’une « boucle de reboot mode protégé »
- Activez le logging de l’émulateur pour resets et exceptions.
- Confirmez que vous chargez l’IDT avant de régler PE.
- Validez la base/limit de la GDT et que les descripteurs sont présents et typés correctement.
- Confirmez le far jump après activation de PE et que le sélecteur CS pointe vers un segment code.
- Réglez SS:SP sur une pile protégée connue tôt.
- Si ça reboot toujours, ajoutez un petit handler pour #GP et #DF qui halt ; arrêtez la boucle et lisez l’état.
FAQ
1) Pourquoi le mode protégé a‑t‑il « sauvé les PC » ?
Il a introduit des frontières appliquées matériellement. C’est la base pour des OS multitâches stables, l’isolation sécurisée, et la capacité d’exécuter des charges complexes sans qu’une appli possède toute la machine.
2) Pourquoi il a « torturé les développeurs » spécifiquement sur le 286 ?
Parce que DOS et le BIOS étaient des écosystèmes mode réel, et le 286 n’offrait pas de chemin propre, rapide et architecturé de retour au mode réel après activation de la protection. Les développeurs devaient choisir : compatibilité ou capacité — ou des transitions bricolées.
3) Le 286 pouvait‑il exécuter un vrai système d’exploitation ?
Oui. Le mode protégé existe spécifiquement pour supporter des fonctionnalités OS : protection mémoire, séparation de privilèges, interruptions structurées. C’est juste que le monde logiciel PC dépendait fortement des conventions du mode réel.
4) Quelle est la différence pratique entre segmentation en mode réel et en mode protégé ?
La segmentation en mode réel est arithmétique ; en mode protégé la segmentation est une politique appliquée par des descripteurs (base, limite, privilèges). En mode protégé, le CPU peut vous empêcher d’accéder à de la mémoire à laquelle vous ne devriez pas accéder.
5) Pourquoi la porte A20 est‑elle si importante ?
Parce que si A20 est désactivée, la mémoire au‑dessus de 1 Mo alias dans la basse mémoire. Cela peut corrompre silencieusement des structures critiques. C’est un mécanisme classique de compatibilité rétro avec un mode d’échec aigu.
6) Pourquoi DOS n’a‑t‑il pas simplement basculé en mode protégé et terminé l’affaire ?
Les hypothèses de conception de DOS — mono‑tâche, dépendance au BIOS, accès direct au matériel — ne se mappaient pas proprement aux restrictions du mode protégé. De plus, la base installée et la pression de compatibilité étaient énormes. L’écosystème a évolué par couches : gestionnaires mémoire, extenders, puis finalement de nouveaux OS.
7) Qu’est‑ce que le 386 a changé pour rendre le mode protégé plus utilisable ?
Le 386 a ajouté la pagination et a rendu les transitions de mode et les stratégies de compatibilité beaucoup plus flexibles (incluant le mode virtual 8086). Il a permis une histoire plus pratique de « faire tourner l’ancien tout en construisant du neuf ».
8) Tout cela est‑il encore pertinent si nous sommes tous sur x86‑64 maintenant ?
Oui. Votre machine boot encore via des étapes compatibles mode réel, gère encore des hypothèses de firmware, et dépend toujours de frontières de privilège claires. Les spécificités ont changé ; les schémas de défaillance n’ont pas disparu.
9) Quelle est la meilleure habitude unique pour éviter les bugs de type 286 ?
Rendez les invariants explicites et testez‑les : état A20, position des tables de descripteurs, présence d’un IDT, et « pas d’appels BIOS après le switch ». Traitez‑les comme des garde‑fous de production.
Prochaines étapes réellement utilisables
Si vous construisez ou déboguez quoi que ce soit touchant au boot précoce, au firmware ou aux transitions x86 bas niveau, prenez la leçon du 286 au sérieux : la capacité sans plan de transition sûr devient génératrice d’incidents.
- Notez vos règles de frontière de mode (ce qui tourne en mode réel, ce qui tourne en mode protégé, et ce qui est interdit après le switch).
- Ajoutez un IDT minimal tôt pour que les fautes deviennent diagnostiquables plutôt que des boucles de reboot.
- Rendez la gestion d’A20 explicite et vérifiez‑la avec un motif de test répétable — ne comptez pas sur le folklore.
- Testez sur deux environnements : émulation déterministe pour le debug, plus au moins une cible physique pour attraper les quirks de timing/chipset.
- Préférez la correction ennuyeuse à des transitions ingénieuses. Le chemin astucieux est généralement un reset en imperméable.
Le 286 fut un tournant : il a tenté de tirer le PC vers un monde où l’OS commande. C’était la bonne direction. C’était aussi désordonné. Ce qui, si vous gérez des systèmes en production, devrait vous sembler étrangement familier.