.--. .----------------------------------------------------------------/ /--. | / / | | Master boot record aka hit me harder master / / 10 | | / / | '------------------------------------------------------------/ /------' /__/ Le MBR d'un 80x86 Le but de ce texte est d'exposer le fonctionnement d'un MBR standard et de servir de base à d'éventuels articles sur des sujets connexes. En fait, ce texte couvre le démarrage de l'ordinateur 80x86 et s'arrête avant le démarrage du système d'exploitation. Lorsque l'ordinateur est mit sous tension, le processeur recoit un courant électrique qui a pour effet de le réinitialiser. Ses registres CS:IP se retrouvent alors automatique initialisé avec les valeurs 0FFFFh:0000. Une brève définition des registres du processeur 80x86 est présenté à la fin du texte. Pour l'instant, disons seulement que le registre CS (code segment) est utilisé comme pointeur de base sur le code à exécuter et le registre IP (instruction pointer) est utilisé comme offset (indice) sur ce pointeur de base. Pour en revenir à ce qui nous intéresse, l'adresse 0FFFFh:0000 est l'adresse contenant le code du "POST" présent dans le BIOS. Le "POST" signifie "Power On Self Test" et a pour fonction de faire l'initialisation primaire des périphériques comme la carte vidéo, périphériques de stockage, RAM, ROM, clavier... Une fois les registres du processeur pointant sur cette partie de code, il commance immédiatement à exécuter les instructions. À la fin de toutes ces initialisations se trouve les premières commandes permettant d'entreprendre le chargement du système d'exploitation. Si aucune erreur ne s'est produite, le code recherche quel périphériques de stockage utiliser pour continuer le démarrage. Il initialise par la suite le registre DL avec le numéro de périphérique et génère int 19h. Un int ou "interrupt" est une série de fonction de bas niveau. Un int est généralement accompagné de paramètres, dans ce cas si déposé dans le registre DL. Un int 19h, fonction du BIOS, a pour effet de charger en mémoire à l'adresse 0000:7C00h le premier secteur physique (secteur 1, cylindre 0, tête 0) de l'unité de stockage désigné en paramètres. L'ordre suivi par le BIOS pour déterminer quel unité utiliser est déterminé par la configuration établie sur chaque système (ex : A:, C: ..). Si l'unité de stockage choisi est un disque dur, le premier secteur mit en mémoire sera le MBR tandis que pour une disquette, ce sera le "boot sector". Le MBR a pour unique tâche de déterminer à quel disque donner le contrôle pour démarrer un système d'exploitation tandis que le boot sector est de démmarer ce système d'exploitation. Rapidement, on peut conclure qu'un disque contient un seul MBR au tout premier secteur physique mais peut par contre contenir plusieurs boot sector, i.e un sur chacun des premiers secteur logique de chaque partition. Dans le cas d'une disquette, elle ne contient aucun MBR puisqu'elle ne peut-être partitionné et contient évidemment qu'un seul boot sector utilisé pour démarrer le système d'exploitation. Pendant tout ce temps, le BIOS n'a aucune notion de ce qu'il a chargé en mémoire. Par contre, dans les deux cas possibles il vérifie que le secteur chargé sois bien terminé par deux octets possédant la valeur 55AAh i.e à l'offset 1FEh. Ces deux octets servent de signature au secteur et permettent de s'assurer qu'il est bien un BS ou un MBR. Si vous modifier cette signature pour "00 00", vous aurez un message semblable : "Boot Record Signature 55AA Not Found, 0000 Found". Par la suite, si tout est valide le BIOS saute à l'adresse 0000:7C00h et le processeur débute l'exécution des instructions du MBR appelé "master bootstrap loader code". Voici la strucure du MBR: À l'offset Taille Description ----------------------------------------------------------------------- 00h 446 octets master bootstrap loader code 1BEh 16 octets enregistrement pour la partition 1 1CEh 16 octets enregistrement pour la partition 2 1DEh 16 octets enregistrement pour la partition 3 1EEh 16 octets enregistrement pour la partition 4 1FEh 2 octets a la valeur 55AAh si le MBR est valide En regardant le tableau précédant, on remarque quatres enregistrements constituants la table de partition. La table de partition est un tableau de quatre enregistrements chacun contenant dix informations spécifiques à chaque partition primaire. Chacun des enregistrement débute respectivement à l'offset 1BEh, 1CEh, 1DEh, 1FEh. Le tableau suivant décrit les champs présents dans une table de partition. À l'offset Taille Description ----------------------------------------------------------------------- 00h octet détermine si la partition doit être utilisé pour booter (80h=oui 00h=non) 01h octet tête de départ 02h 6 bits secteur de départ 03h 10bits cylindre de départ 04h octet type de volume 05h octet tête de fin 06h 6bit secteur de fin 07h 10bits cylindre de fin 08h dword nombre de secteur avant la partition 12h dword taille de la partition en secteur Voici à titre "extrêmement" informatif uniquement une liste de valeur pour le type de volume: 00h empty 01h DOS 12-bit FAT 02h XENIX root file system 03h XENIX /usr file system (obsolete) 04h DOS 16-bit FAT (up to 32M) 05h DOS 3.3+ extended partition 06h DOS 3.31+ Large File System (16-bit FAT, over 32M) 07h QNX 07h OS/2 HPFS 07h Windows NT NTFS 07h Advanced Unix 08h AIX bootable partition, SplitDrive 09h AIX data partition 09h Coherent filesystem 0Ah OS/2 Boot Manager 0Ah OPUS 0Ah Coherent swap partition 10h OPUS 11h OS/2 Boot Manager hidden 12-bit FAT partition 12h Compaq Diagnostics partition 14h (resulted from using Novell DOS 7.0 FDISK to delete Linux Native part) 14h OS/2 Boot Manager hidden sub-32M 16-bit FAT partition 16h OS/2 Boot Manager hidden over-32M 16-bit FAT partition 17h OS/2 Boot Manager hidden HPFS partition 18h AST special Windows swap file 24h NEC MS-DOS 3.x 3Ch PowerQuest PartitionMagic recovery partition 40h VENIX 80286 42h SFS (Secure File System) by Peter Gutmann 50h Disk Manager, read-only partition 51h Disk Manager, read/write partition 51h Novell??? 52h CP/M 52h Microport System V/386 56h GoldenBow VFeature 61h SpeedStor 63h Unix SysV/386, 386/ix 63h Mach, MtXinu BSD 4.3 on Mach 63h GNU HURD 64h Novell NetWare 65h Novell NetWare (3.11) 70h DiskSecure Multi-Boot 75h PC/IX 80h Minix v1.1 - 1.4a 81h Minix v1.4b+ 81h Linux 81h Mitac Advanced Disk Manager 82h Linux Swap partition 83h Linux native file system (ext2fs/xiafs) 84h OS/2-renumbered type 04h partition (related to hiding DOS C: drive) 93h Amoeba file system 94h Amoeba bad block table A5h FreeBSD, BSD/386 B7h BSDI file system (secondarily swap) B8h BSDI swap partition (secondarily file system) C1h DR DOS 6.0 LOGIN.EXE-secured 12-bit FAT partition C4h DR DOS 6.0 LOGIN.EXE-secured 16-bit FAT partition C6h DR DOS 6.0 LOGIN.EXE-secured Huge partition C7h Syrinx Boot DBh CP/M, Concurrent CP/M, Concurrent DOS DBh CTOS (Convergent Technologies OS) E1h SpeedStor 12-bit FAT extended partition E3h DOS read-only E4h SpeedStor 16-bit FAT extended partition F2h DOS 3.3+ secondary F4h SpeedStor FEh LANstep FFh Xenix bad block table Toute ces informations, contenu dans la table de partition seront utilisées ultérieurement lors de l'exécution du MBR pour déterminer où se retrouve le boot sector à chargé en mémoire. Lorsque vous installer un boot loader (XOSL par exemple), il modifie le MBR plus particulièrement le "master bootstrap loader code" pour lui permettre de prendre le contrôle au démarrage et d'afficher un choix à l'utilisateur. Si vous n'avez pas de boot loader, le code vérifiera pour trouver la partition active. Avec les informations concernant cette partition, le code mettra en mémoire le premier secteur logique (BS) et transfèrera le contrôle à cette adresse, le processeur débutant immédiatement l'exécution du code du BS. Si vous trouver utile de savoir ce que fait concrètement le MBR continuer à lire. Voici le master bootstrap loader code d'un de mes disque dur sans boot loader. Par contre, il se peut que le votre diffère légèrement. On déplace le code ailleur puisque l'on veut charger le BS à l'adresse où nous sommes présentement 0000:7C00 FA CLI Empèche les interruptions 0000:7C01 33C0 XOR AX,AX Stack segment à 0000 0000:7C03 8ED0 MOV SS,AX 0000:7C05 BC007C MOV SP,7C00 Stack pointer à 7c00 0000:7C08 8BF4 MOV SI,SP SI à 7c00 0000:7C0A 50 PUSH AX 0000:7C0B 07 POP ES 0000:7C0C 50 PUSH AX 0000:7C0D 1F POP DS 0000:7C0E FB STI Remet les interruptions 0000:7C0F FC CLD Clear direction 0000:7C10 BF0006 MOV DI,0600 Destiny index pointer (où on va copier le mbr) 0000:7C13 B90001 MOV CX,0100 on déplacera 256 mots (512 octets) 0000:7C16 F3A5 REP MOVSB déplace le MBR de 0000:7c00 à 0000:0600 0000:7C18 EA1D060000 JMP 0000:061D jmp to NOUVEL_EMPLACEMENT NOUVEL_EMPLACEMENT: maintenant à 0000:0600 0000:061D BEBE07 MOV SI,07BE source index register à la première entrée de la table de partition 0000:0620 B304 MOV BL,04 compteur pour 4 T. de P. LOOP1: recherche une partition valide 0000:0622 803C80 CMP BYTE PTR [SI],80 est-ce la partition active? 0000:0625 740E JZ PARTACTIVE_TROUVE oui 0000:0627 803C00 CMP BYTE PTR [SI],00 sinon, est-ce une partition inactive? 0000:062A 751C JNZ PARTNON_ACTIVE oui 0000:062C 83C610 ADD SI,+10 SI pointe sur le prochain enregistrement 0000:062F FECB DEC BL décrémente le compteur 0000:0631 75EF JNZ LOOP1 recommence si on a pas atteind la dernière entrée 0000:0633 CD18 INT 18 si on a atteind la dernière et aucune partition n'est active, goto rombasic PARTACTIVE_TROUVE: on a trouvé la partition active 0000:0635 8B14 MOV DX,[SI] initialise DH/DL pour l'INT 13 DH=tête DL=numéro de disque 0000:0637 8B4C02 MOV CX,[SI+02] initialise CH/CL pour l'INT 13 CH=numéro de cylindre CL=numéro de secteur 0000:063A 8BEE MOV BP,SI sauvegarde le pointeur de la partition LOOP2: On s'assure qu'il n'y a qu'une partition active 0000:063C 83C610 ADD SI,+10 SI pointe sur le prochain enregistrement 0000:063F FECB DEC BL décrémente le compteur 0000:0641 741A JZ LIRE_BOOT_SECTOR une seule partition active a été trouvé parmis les quatres, commence le boot 0000:0643 803C00 CMP BYTE PTR [SI],00 est-ce une partition inactive? 0000:0646 74F4 JZ LOOP2 oui, donc continue PARTNON_ACTIVE: la partition n'était pas une partition inactive, affiche un message 0000:0648 BE8B06 MOV SI,068B met l'adresse du message dans si AFFICHE_MSG: FONCTION POUR AFFICHER UN MSG (SI POINTE SUR LE MSG) 0000:064B AC LODSB charge le premier caractère du message dans ax 0000:064C 3C00 CMP AL,00 détermine si on est au caractère \0 (fin du message) 0000:064E 740B JZ STOP oui 0000:0650 56 PUSH SI sauvegarde SI 0000:0651 BB0700 MOV BX,0007 option d'affichage (BH video page, BL color to use) 0000:0654 B40E MOV AH,0E fonction 0e (affiche 1 caractère) 0000:0656 CD10 INT 10 interupt 10 (bios) 0000:0658 5E POP SI restaure SI 0000:0659 EBF0 JMP AFFICHE_MSG affiche la prochaine lettre du message STOP: 0000:065B EBFE JMP STOP boucle infini LIRE_BOOT_SECTOR: lit le boot sector de la partition active 0000:065D BF0500 MOV DI,0005 on essaira de lire 5 fois INT13RETRY: 0000:0660 BB007C MOV BX,7C00 destination de la lecture 0000:0663 B80102 MOV AX,0201 lit un secteur à l'adresse SI ah=2h (fonction 2 du int 13) al=1h (quantité) 0000:0666 57 PUSH DI sauvegarde DI 0000:0667 CD13 INT 13 lit le secteur à 0000:7c00 0000:0669 5F POP DI restaure DI 0000:066A 730C JNB INT13OK si il y a eu erreur 0000:066C 33C0 XOR AX,AX AX=0 0000:066E CD13 INT 13 réinitialise le disque (int 13h fonction 0h) 0000:0670 4F DEC DI décrémente DI 0000:0671 75ED JNZ INT13RETRY recommence si DI différent de 0 0000:0673 BEA306 MOV SI,06A3 on a pas réussi à loader le boot sector SI pointe à l'adresse du message d'erreur 0000:0676 EBD3 JMP AFFICHE_MSG affiche le message INT13OK: 0000:0678 BEC206 MOV SI,06C2 message d'erreur 0000:067B BFFE7D MOV DI,7DFE pointe sur la signature 0000:067E 813D55AA CMP WORD PTR [DI],AA55 est-elle équivalente à 55AAh ?? 0000:0682 75C7 JNZ AFFICHE_MSG non, on affiche le message ( boot sector not valid.. ) 0000:0684 8BF5 MOV SI,BP sinon, 0000:0686 EA007C0000 JMP 0000:7C00 transfère le contrôle au boot sector de la partition active, SI pointe sur l'enregistrement correspondant dans la table de partition Et le boot sector débute le chargement du système d'exploitation... Si vous étiez complètement perdu dans ce code peut-être devriez-vous lire quelques peu sur le langage d'assemblage. Un mot très rapide sur le langage d'assemblage pour les non-initié: Les registres (16-bit uniquement) utilisé dans notre code: Leur nom et utilité: AX Accumulator BX Base register CX Counting register DX Data register DS Data segment register ES Extra segment register SS Battery segment register CS Code segment register BP Base pointers register SI Source index register DI Destiny index register SP Battery pointer register IP Next instruction pointer register F Flag register Certains registres dont AX, BX, CX, DX peuvent être séparé en deux parties: les bits du haut et ceux du bas. La partie du haut de AX se nomme AH et la partie du bas AL (High et Low). De cette façon, on peut manipuler un octet à la fois. Des instructions... : MOV: déplace une valeur dans un opérande ex: MOV AX, 80h <- met 80h dans le registre AX DEC: décrémente de 1 l'opérande ex: DEC AX JXX: instruction JUMP. JMP: jump inconditionel (on saute à l'adresse dans tous les cas) JNZ: jump not zero JZ: jump zero INT: une interruption. Il existe quatre types d'interruption: Hardware Interne (CPU) Hardware Externe (clavier, imprimante..) Software (BIOS et OS) Les INT utilisé dans le MBR sont des interruptions logiciels du BIOS. Ces interruptions sont des fonctions mis à notre disposition par le BIOS. Les interruptions sont séparé en catégories. Certaines interruptions du BIOS par exemple: Int 10H: Video Int 16H: Clavier Int 17H: Imprimante Chaque interruption regroupe plusieurs fonction. Pour Int 16h: 00H lit un caractère du clavier 01H lit l'état du clavier Pour utiliser une fonction on initialise ah avec le numéro de la fonction et appele l'interruption. ex: mov ah, 00h int 16h Note: On doit souvent mettre d'autre paramètre dans d'autre registre. XOR: ou exclusif (bit à bit) XOR AX,BX met le résultat dans AX XOR AX,AX donne évidemment toujours 0. POP et PUSH (opérateur de la pile système). PUSH: met une valeur sur la pile système POP: met la première valeur sur la pile système dans l'opérande ex: mov AX, 1h push AX pop BX BX sera égal à 1h et à AX :) J'espère que ce cours texte vous aura été utile. Orange_