ECRIRE UN SECTEUR DE BOOT
(c)1997 Jeff Weeks and Code X software


Traduit par groar, abyssal.homelinux.org.
Le texte original peut-être trouvé à l' adresse : http://abyssal.homelinux.org/@@%20OSdev/vo/bootwrit.html Si vous avez des suggestions à me faire pour cette traduction mailez moi : root@abyssal.homelinux.org gRooOooOoooOOOAr



Ecrire votre propre secteur de boot est probablement plus facile que vous ne le pensez. Tout ce que vous avez besoin de savoir est comment boote un processeur Intel. Les deux derniers octets d un secteur de boot sont 0xAA55 (à l offset 510), et il est situé sur le tout premier secteur du disque. Donc, le BIOS contrôle simplement le périphérique 0 (A:) pour trouver ce code. S' il n' est pas trouvé il va alors regardé le deuxième périphérique pouvant être booté ( souvent le premier disque dur). Si un secteur de boot valide est trouvé, il est chargé en mémoire à l' emplacement mémoire 0:07C0h.

Donc, tout ce que vous avez à faire est écrire un secteur de boot, l' assembler en tant qye fichier binaire (il n' y a pas de format ou de header dans un secteur de boot), et l' écrire sur le premier secteur de votre disque (disquette ou disque dur) La meilleure solution pour faire cela est d' utiliser nasm ("The netwide assembler" peut produire des fichiers binaires plats) ou assembler dans un .EXE DOS et enlever les 512 premiers octets. Vous pouvez écrire le secteur de boot sur le secteur 1 du disque en utilisant l' INT 13h AH=02h du BIOS.

Simple non ? Bien, au cas où vous ne comprendriez toujours pas, voici un petit ssecteur de boot provenant de PolyOS qui passe simplement en mode protégé, après avoir vérifié ke vous avez un ordinateur 386 ou +. Actuellement, il charge dans le superblock PolyFS et vérifie si il est valide,mais c' est tout. Bientôt il chargera le kernel et jumpera dessus. Ce secteur de boot a été écrit avec Nasm.
; ------------------------------------------------------------------------
; Code du boot loader de PolyOS     (c)1997 Jeff Weeks of Code X Software
; ------------------------------------------------------------------------
; This little bit of assembly is the boot loader for my operating system.
; ------------------------------------------------------------------------

[BITS 16]       ; the bios starts out in 16-bit real mode
[ORG 0]

; ------------------------------------------------------------------------
; SECTEUR UN: LE CHARGEUR DE BOOT
; ------------------------------------------------------------------------
; Ce secteur détecte votre processeur.  Si un 386 est trouvé, il charge le
; kernel depuis le disque et l'exécute(du moins il le fera dans l' avenir:)
; ------------------------------------------------------------------------

jmp start       ; skip over our data and functions

; -------------------------------------
; Données utilisées pendant le chargement
; ------------------------------------------------------------------------
        bootdrv         db 0
        bootmsg         db 'Démarrage de PolyOS (c)1997 Cipher of Code X',13,10,0
        loadmsg         db 'Chargement du kernel',13,10,0
        jumpmsg         db 'Jumping to kernel',13,10,0
        rebootmsg       db 'Pressez une touche pour redémarrer',13,10,0

        ; utilisées dans la détection du processeur
        processormsg    db 'Vérification du processeur 386+ : ',0
        need386         db 'Désolé... un 386+ est requis!',13,10,0
        found386        db 'Excellent!',13,10,0

        ; utilisées lors du passage en mode protégé
        a20msg          db 'Setting A20 address line',13,10,0
        pmodemsg        db 'Setting CR0 -> Entering PMode',13,10,0

        ; Voici les emplacements de mon IDT et mon GDT.  Rappelez-vous, Intel sont 
	  ; des processeurs "little endian", donc, ceux-ci sont en ordre inversé. 
        ; Notez en outre que le l' idt et le le gdt acceptent une adresse de 32 bits et la 
        ; limite de 16 bits, donc, ceux-ci sont des variables 48-bit.
        pIDT            dw 7FFh         ; limit of 256 IDT slots
                        dd 0000h        ; commence à 0000

        pGDT            dw 17FFh        ; limit of 768 GDT slots
                        dd 0800h        ; commence à 0800h (après IDT)

; ------------------------------------------
; Fonctions utilisées pendant le chargement du boot
; ------------------------------------------------------------------------
        detect_cpu:
                mov si, processormsg    ; Dis à l' utilisateur ce que l' on est en train de faire
                call message

                ; teste si un 8088/8086 est present (flag bits 12-15 will be set)
                pushf                   ; sauvegarde les valeurs originales des flags
                
                xor ah,ah               ; ah = 0
                push ax                 ; copie ax dans les flags
                popf                    ; with bits 12-15 clear
                
                pushf                   ; Read flags back into ax
                pop ax       
                and ah,0f0h             ; vérifie que les bits 12-15 sont définis
                cmp ah,0f0h
                je no386                ; aucun 386 détecté (8088/8086 présent)

                ; teste pour un 286 (les bits 12-15 sont effacés)
                mov ah,0f0h             ; définie les bits 12-15
                push ax                 ; copy ax onto the flags
                popf
                
                pushf                   ; copy the flags into ax
                pop ax
                and ah,0f0h             ; check if bits 12-15 are clear
                jz no386                ; aucun 386 détecté (un 80286 présent)
                popf                    ; pop the original flags back
                
                mov si, found386
                call message
                
                ret                     ; aucun 8088/8086 ou 286, donc c' est un 386
         no386:
                mov si,need386          ; dis à l' utilisateur le problème
                call message
                jmp reboot              ; et reboot quand on presse une touche
                     
;       ------------------------------------------------------------------
        message:                        ; Affiche ds:si à l' écran.
                lodsb                   ; charge les bytes contenus dans ds:si dans al
                or al,al                ; teste si le caractère est 0 (fin)
                jz done
                mov ah,0eh              ; affiche le caractère
                mov bx,0007             ; attribute
                int 0x10                ; appelle le BIOS
                jmp message
        done:
                ret
;       ------------------------------------------------------------------
        getkey:
                mov ah, 0               ; attend une touche pressée
                int 016h
                ret

;       ------------------------------------------------------------------        
        reboot:
                mov si, rebootmsg       ; être poli, et dire qu' on reboote :)
                call message
                call getkey             ; et ensuite attendre qu' on presse une touche :)

                db 0EAh                 ; machine language to jump to FFFF:0000 (reboot)
                dw 0000h
                dw 0FFFFh
                ; aucun ret recquis; on reboote! (Hey, j'ai juste sauvé un byte :)

; -------------------------------------------
; The actual code of our boot loading process
; ------------------------------------------------------------------------
start:
        mov ax,0x7c0    ; BIOS puts us at 0:07C0h, so set DS accordinly
        mov ds,ax       ; Therefore, we don't have to add 07C0h to all our data

        mov [bootdrv], dl ; on sauve rapidement de quel périphérique on boote

        cli             ; clear interrupts while we setup a stack
        mov ax,0x9000   ; cela semble être la place idéale pour la pile
        mov ss,ax
        mov sp,0xffff   ; let's use the whole segment.  Pourquoi pas?  On peut :)
        sti             ; put our interrupts back on
        
        ; Interestingly enough, apparently the processor will disable 
        ; interupts itself when you directly access the stack segment!
        ; Atleast it does in protected mode, je ne suis pas sûr pour le mode réel.
        
        mov si,bootmsg  ; affiche le message de démarrage
        call message

        call detect_cpu ; vérifie qu' on ait bien un 386

.386    ; use 386 instructions from now on (I don't want to manually include
        ; operand-size(66h) or address-size(67h) prefixes... it's annoying :)

        mov si,loadmsg  ; informe l' utilisateur que le kernel va être chargé
        call message
        call getkey

read_me:
        ; d abord réinitialise le contrôleur de disque
        xor ax, ax
        int 0x13
        jc reboot       ; reboot quand il y a une erreur

        ; then load in the PolyFS superblock
        mov ax,0x09000          ; superblock goes to 9000:0000 (above stack)
        mov es,ax
        xor bx,bx

        ; J aurai pu condenser un peu ces high/low movs 8-bit en un seul mov de 16-bit
        ; mais, pour être simple, je le laisserai comme cela, à moins que ce ne soit nécessaire.
        mov ax,0x0202           ; charge un bloc (deux secteurs)
        mov ch,0                ; cylindre = 0
        mov cl,3                ; secteur = 2 (commence au secteur 1 , pas 0)
        mov dh,0                ; head = 0 = side one
        mov dl,[bootdrv]        ; disk = d' où on boote
        int 0x13                ; lisez le
        jc read_me              ; si il y a une erreur alors on essaye encore.
                                ; Il n' y pas souvent d' erreur mais cela exige 
                                ; quelques essais.  Bien sur, cela peut faire une 
                                ; boucle infinie... mais seulement sur un mauvais disque...
        
        ; Regarde si on a un super block valide (BTW: ES still equals 0x9000)
        mov di, 0               ; offset of PolyFS magic signature
        mov si, polymagic       ; offset of PolyFS magic to check for (in ds)
        cmpsw                   ; compare ES:[DI] avec DS:[SI]
        jnz reboot              ; reboot si il y a une erreur (autrement, nous avons PolyFS)

	; Dans l' idéal il serait bien de chargé le kernel ici

        mov si, a20msg          ; informe l utilisateur que nous sommes en train de définir la ligne A20 
        call message

        ; set A20 line
        cli                     ; plus d' interruptions :)
        xor cx, cx
clear_buf:
        in al, 64h              ; get input from keyboard status port
        test al, 02h            ; test the buffer full flag
        loopnz clear_buf        ; fais une boucle jusqu' à ce que le buffer soit vide
        mov al, 0D1h            ; clavier: écrire sur le port de sortie
        out 64h, al             ; output command to keyboard
clear_buf2:
        in al, 64h              ; attend que le buffer soit vide encore
        test al, 02h
        loopnz clear_buf2
        mov al, 0dfh            ; clavier: définit A20
        out 60h, al             ; l' envoie au contrôleur de clavier
        mov cx, 14h
wait_kbc:                       ; Ceci est une approximation. un délai de 25uS pour attendre
        out 0edh, ax            ; que le controleur de clavier exécute notre  
        loop wait_kbc           ; commande.

        ; the A20 line is on now.  Let's load in our ITD and GDT tables...
        ; Ideally, there will actually be data in their locations (by loading 
        ; the kernel)
        lidt [pIDT]
        lgdt [pGDT]

        ; maintenant nous entrons en pmode...
        mov si, pmodemsg
        call message
        call getkey

        mov eax, cr0            ; load the control register in
        or  al, 1               ; set bit 1: pmode bit
        mov cr0, eax            ; copy it back to the control register
        jmp $+2                 ; and clear the prefetch queue
        nop
        nop

        ; saut juqu' au kernel que nous avons chargé...
        ; Pour le moment, nous rebooterons simplement (cela ne marche pas vraiment 
        ; en mode protégé, mais il reboot :)
        db 0xEA
        dw 0x0000
        dw 0xFFFF

        ; Le secteur de boot est supposé devoir avoir 0xAA55 à la fin du secteur 
        ; (le word à 510 bytes) pour être chargé par le BIOS...
        times 510-($-$$) db 0
        dw 0xAA55