neku
Codeur roumain
Voici, j'ai commencé à écrire mon système d'exploitation
Si comme moi vous êtes intéressé par la création d'un OS, je posterai régulièrement; Des tutos, des explications, les codes sources ...
J'ai donc actuellement commencé l'écriture du bootsector (secteur de démarrage)
512octets max
Ecrit pour NASM
bootsect.asm
fat12.asm
setup.asm
a20.asm
J'éditerai prochainement ce poste pour donner des liens expliquant comment une machine démarre et dans quel état elle se trouve au moment de son démarrage.
Si comme moi vous êtes intéressé par la création d'un OS, je posterai régulièrement; Des tutos, des explications, les codes sources ...
J'ai donc actuellement commencé l'écriture du bootsector (secteur de démarrage)
512octets max
Ecrit pour NASM
bootsect.asm
Code:
;Ce secteur de démarrage à été réalisé par Neku
;rb_neku@hotmail.com
;Ce secteur de démarrage est sous license GPL
[ORG 0]
jmp 07C0h:start ;On se déplace au segment 0700 (la ou le bios charge le bootsector)
%include "fat12.asm"
%define buffer 0x7e00
%define file 0x8000
setup db 'NEKU32',0
kernelname db 'SETUP BIN',0
loadk db 'Starting...',10,13,0
knf db 'Kernel not found !',10,13,0
mpause db 'Presse any key to continue !',10,13,0
%define bootdrive 0
LOAD_ADDR DW 9020h
start:
cli
mov AX,9000h
mov SS,AX
mov SP,0h
sti
;mov es, ax
;push ax
;xor ax, ax
;mov ds, ax
;mov ax, 7c00h
;mov si, ax
;mov di, ax
;mov cx, 0100h
;rep movsw
;mov ax, go
;push ax
;retf
jmp go
go:
;Mise à jour des registres de segments
mov ax, cs
mov ds, ax
mov es, ax
;call detect_cpu
.386 ;A partir d'ici ou utilisera les instruction 386
jmp load
load:
mov si, loadk
call print
mov ax, 19 ;Premier secteur de la FAT
lo1:
push ax
mov bx, buffer
call readsector
mov cx, 16
mov dl, 1
lo2:
push cx
mov di, file
mov bx, buffer
call buf2file
mov bx, file
call decompfile
mov si, filename
mov di, kernelname
mov cx, 11
repe cmpsb
jz kfound
next1:
inc dl
pop cx
loop lo2
pop ax
cmp ax, 32
jge NotFound
inc ax
jmp lo1
kfound:
mov si, kernelname
call print
pop cx
pop ax
mov ax, 1
call sl2p
mov bx, buffer
mov ah, 02
mov al, 9
mov dl, bootdrive
int 13h
mov bx, 0
push bx
mov ax, [LOAD_ADDR]
mov es, ax
lo:
mov ax, [cluster]
pop bx
add ax, 31
call readsector
add bx, 512
push bx
mov bx, buffer
mov ax, [cluster]
call getnextcluster
cmp ax, 0x0FF8
jb lo
cmp word [LOAD_ADDR], 9020h
jne finish
mov ax, ds
mov es, ax
mov si, setup
mov di, kernelname
mov cx, 8
rep movsb
mov [LOAD_ADDR], word 100h
jmp load
finish:
mov ax, word 0x9020
jmp 0x9020:0
NotFound:
mov si, knf
call print
call keywait
int 19h
jmp $
;===============
;Reset_Drive
;===============
;reset_drive:
; mov ax, 0
; mov dl, 0
; int 13h
; jc reboot ;Si il y a une erreur on reboot ;)
;===============
;/Reset_Drive
;===============
;===============
;Keywait
;===============
keywait: ;On attend que l'utilisateur appuye sur une touche
mov si, mpause
call print
mov ah, 0 ;Attende d'une touche
int 016h
ret
;===============
;/Keywait
;===============
;===============
;Reboot
;===============
reboot: ;On redemarre la machine
call keywait ;On attend que l'utilisateur appuye sur une touche
db 0eah ;saut à FFFF:0000 (reboot)
dw 0000h
dw 0FFFFh
;===============
;/Reboot
;===============
;===============
;Print
;===============
print: ;Fonction permettant l'affichage de message à l'écran
lodsb ;en utilisant l'interruption 10h
or al, al ;Si al = 0
jz done ;Done
mov ah, 0Eh
mov bx, 0007
int 0x10
jmp print
done:
ret
;===============
;/Print
;===============
;hang:
; jmp hang ;Hang !
times 510-($-$$) db 0
dw 0AA55h
[SEGMENT .bss]
filename resb 8
ext resb 3
Code:
;driver permettant au secteur de boot de gerer la fat12
;Merci à Alaa eddine KADDOURI
%define cluster 0xFF0
;=============
;sl2p
;Conversion Secteur logique -> Physique
;Entrée : AX = numéro logique du secteur (0..2879)
;Sotie:
;cl = numéro du secteur (1..18)
;dh = numéro de la piste (0..79)
;ch = numéro de la face (0 ou 1)
;=============
sl2p:
xor dx, dx ;Préparation d'un division
push ax ;Sauvegarde de AX
push bx ;Sauvegarde de BX
mov bx, 18 ;18 Secteurs/Piste
div bx ;On divise le n° de secteur par le nombre de secteurs/piste pour récupérer
;le nombre de secteurs sur la piste
mov cx, dx ;On place le reste la division dans cx (pour int 13h)
xor dx, dx ;Préparation de la division
mov bx, 2 ;On divise le reste par 2 de la division précédente
div bx ;pour récupérr sur quelle tête se trouve le secteur
pop bx ;restauration de bx
mov dh, dl ;on place le numéro de tête dans dh (pour int 13h)
ror ah, 2 ;On décale 2 fois à droite ah
xchg al, ah ;et on échange ah et al
mov dl, 18 ;18 secteurs/piste
sub dl, cl ;On soustrait le reste de la division qui permet d'obtenir
;le numéro de secteur sur la piste
inc cl ;et en ajoutant 1 on obtient le n° de piste
or cx, ax ;sans oublier d'ajouteur les bits de AX
mov dl, al ;On a le n° de tête dans AL
pop ax ;On restaure AX
ret
;=============
;/sl2p
;=============
;=============
;readsector
;Lecture d'un secteur
;Entrée :
;AX = numéro logique du secteur (0..2879)
;BX = le buffer qui recevra les données
;Sortie : Aucune
;=============
readsector:
push ax ;On sauvegarde AX
push dx ;On sauvegarde DX
call sl2p ;Conversion secteur logique -> secteur physique
mov ah, 02h ;Fonction de lecture
mov al, 01h ;d'un secteur
int 13h
pop dx ;On restaure DX
pop ax ;On restaure AX
ret
;=============
;/readsector
;=============
;=============
;buf2file
;Extraction d'une entrée du répertoire principale depuis un buffer
;Entrée :
;BX = buffer source 512 octets
;DL = Numéro de l'entrée (1..16)
;DI = buffer cible 32 octets
;Sortie : Aucune
;=============
buf2file:
push ax ;On sauvegarde AX
push bx ;On sauvegarde BX
push cx ;On sauvegarde CX
push si ;On sauvegarde SI
mov al, 32 ;On calcule le rang de l'entrée qu'on veut extraire
mul dl
sub ax, 32
add bx, ax ;On ajoute le rang au buffer
mov si, bx ;Puis on affectue notre copie
mov cx, 16 ;Chaque entrée contient 32 octets
.getfile:
movsw
loop .getfile
.fin
pop si ;On restaure SI
pop cx ;On restaure CX
pop bx ;On restaure BX
pop ax ;On restaure AX
ret
;=============
;/buf2file
;=============
;=============
;decompfile
;Décomposition des entrées du répertoire principal
;Entrée:
;BX = le buffer qui contient l'entrée à décomposée (32 octets)
;DI = le buffer du nom de fichier
;Sortie:
;filename = nom du fichier
;attr = contient les attributs
;cluster = contient le 1er cluster du fichier
;=============
decompfile:
push ax
push bx
push cx
mov si, bx
mov di, filename
mov cx, 11
.getfilename:
lodsb
cmp cx, 11
jne .stock
cmp al, 31
jg .stock
mov al, 0
stosb
jmp .nofile
.stock:
stosb
loop .getfilename
add bx, 26
mov si, bx
mov di, cluster
mov cx, 3
rep movsw
.nofile:
pop cx
pop bx
pop ax
ret
;=============
;/decompfile
;=============
;=============
;getnextcluser
;Lecture du prochain cluster dans AX
;Entrée :
;BX = buffer source 512 octets
;AX = numéro du cluster courant (0..2879)
;Sortie:
;AX = numéro du cluster suivant
;REMARQUE : La formule pour connaître le secteur correspondant à un cluster :
;numsecteur = 33 + numcluster - 2
;33 = n° du premier secteur dans une FAT12
;2 = le nombre d'élément de 12 bits utilisés pour distingué une FAT2
;La table FAT12 commence par : F0F FFF
;=============
getnextcluster:
push bx
push bx
add ax, 1
mov bx, 12
mul bx
mov bx, 8
div bx
pop bx
add bx, ax
cmp dx, 4
je .R4
.R0:
sub dx, 2
mov ax, word [bx]
sar ax, 4
and ax, 0000111111111111b
jmp .endr
.R4:
sub bx, 1
mov ax, word [bx]
and ax, 0000111111111111b
.endr:
pop bx
ret
;=============
;/getnextcluster
;=============
Code:
[BITS 16]
%include "a20.asm"
msg_loadk db 'Launching Kernel ...',10,13,0
errproc db '386+ Require !',10,13,0
_start:
cli
mov AX,9000h
mov SS,AX
mov SP,0h
sti
mov ax, cs
mov es, ax
mov ds, ax
mov si, msg_loadk
call print
call detect_cpu ;On vérifie le processeur
call A20Active ;On active la porte A20
;===============
;Print
;===============
print: ;Fonction permettant l'affichage de message à l'écran
lodsb ;en utilisant l'interruption 10h
or al, al ;Si al = 0
jz done ;Done
mov ah, 0Eh
mov bx, 0007
int 0x10
jmp print
done:
ret
;===============
;/Printf
;===============
;===============
;CPU Detect
;===============
detect_cpu: ;On verifie que le processeur est un 386+
;Pour savoir si le processeur est un 386+ les flags 12-15 sont définits
push si
pushf ;On sauvegarde la valeur d'origine des flags
xor ah, ah ;ah = 0
push ax
popf
pushf
pop ax
and ah, 0x0f ;vérification des bits 12-15
cmp ah, 0x0f
je no386 ;-> Processeur = 8088/8086
;286 ? (bits 12-15 vide)
mov ah, 0x0f
push ax
popf
pushf
pop ax
and ah, 0x0f
jz no386 ;-> Processeur = 80286
popf
pop si
ret ;-> Processeur != 8088/8086 ou 286
no386:
mov si, errproc
call print
jmp reboot ;Reboot !
;===============
;/CPU Detect
;===============
Code:
;----------------------------------------------
; Procédures pour l'activation de la porte A20
;----------------------------------------------
A20Active:
push ax
mov ah, 0dfh
call GateA20
or al, al
jz A20Active_ok
stc
A20Active_ok:
pop ax
ret
GateA20:
pushf
cli
call Empty8042
jnz GateA20_fail
out 0edh, ax
mov al, 0D1h
out 64h, al
call Empty8042
jnz GateA20_fail
mov al, ah
out 60h, al
call Empty8042
push cx
mov cx, 14h
GateA20_loop:
out 0edh, ax
loop GateA20_loop
pop cx
GateA20_fail:
popf
ret
Empty8042:
push cx
xor cx, cx
Empty8042_try:
out 0edh, ax
in al, 64h
and al, 2
loopnz Empty8042_try
pop cx
ret