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 contrle
simplement le priphrique 0 (A:) pour trouver ce code. S' il n' est pas trouv
il va alors regard le deuxime priphrique pouvant tre boot ( souvent le premier
disque dur). Si un secteur de boot valide est trouv, il est charg en mmoire l'
emplacement mmoire 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 protg,
aprs avoir vrifi ke vous avez un ordinateur 386 ou +. Actuellement, il charge dans
le superblock PolyFS et vrifie si il est valide,mais c' est tout. Bientt
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 dtecte votre processeur. Si un 386 est trouv, il charge le
; kernel depuis le disque et l'excute(du moins il le fera dans l' avenir:)
; ------------------------------------------------------------------------
jmp start ; skip over our data and functions
; -------------------------------------
; Donnes utilises pendant le chargement
; ------------------------------------------------------------------------
bootdrv db 0
bootmsg db 'Dmarrage 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 redmarrer',13,10,0
; utilises dans la dtection du processeur
processormsg db 'Vrification du processeur 386+ : ',0
need386 db 'Dsol... un 386+ est requis!',13,10,0
found386 db 'Excellent!',13,10,0
; utilises lors du passage en mode protg
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 (aprs IDT)
; ------------------------------------------
; Fonctions utilises 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 ; vrifie que les bits 12-15 sont dfinis
cmp ah,0f0h
je no386 ; aucun 386 dtect (8088/8086 prsent)
; teste pour un 286 (les bits 12-15 sont effacs)
mov ah,0f0h ; dfinie 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 dtect (un 80286 prsent)
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 problme
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 caractre est 0 (fin)
jz done
mov ah,0eh ; affiche le caractre
mov bx,0007 ; attribute
int 0x10 ; appelle le BIOS
jmp message
done:
ret
; ------------------------------------------------------------------
getkey:
mov ah, 0 ; attend une touche presse
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 priphrique on boote
cli ; clear interrupts while we setup a stack
mov ax,0x9000 ; cela semble tre la place idale 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 sr pour le mode rel.
mov si,bootmsg ; affiche le message de dmarrage
call message
call detect_cpu ; vrifie 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 rinitialise le contrleur 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 ncessaire.
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' idal il serait bien de charg le kernel ici
mov si, a20msg ; informe l utilisateur que nous sommes en train de dfinir 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: dfinit A20
out 60h, al ; l' envoie au contrleur de clavier
mov cx, 14h
wait_kbc: ; Ceci est une approximation. un dlai de 25uS pour attendre
out 0edh, ax ; que le controleur de clavier excute 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 protg, 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