org 0x0000 ; Adresse de début bootloader

;Définitions de données qui seront chargées par le BIOS
;Informations du pilote VESA
%define VESASignature 512;'VESA', signature de 4 octets
;VESAVersion: dw 0; numéro de version de VBE
;OEMStringPtr: dd 0; Pointeur vers le nom de l'OEM
;Capabilities: dd 0; Possibilités de la carte graphique
%define VideoModePtr VESASignature + 14;: dd 0; Pointeur vers les modes accessibles
;TotalMemory: dw 0; Nombre de blocs mémoire de 64ko
;reserved: times 236 db 0; Complément à 256 octets, taille du bloc
;Informations d'un mode vidéo
%define ModeAttributes VESASignature + 256; Attributs du mode mot
;WinAAttributes: db 0; Attibuts de la fenêtre A octet
;WinBAttributes: db 0; Attibuts de la fenêtre B octet
;WinGranularity: dw 0; Granularité de la fenêtre en ko mot
;WinSize: dw 0; Taille de la fenêtre en ko mot
%define WinASegment ModeAttributes + 8;: dw 0; Segment de la fenêtre A mot
;WinBSegment: dw 0; Segment de la fenêtre B mot
;WinFuncPtr: dd 0; Pointeur vers la fonction "de fenêtrage" double mot
%define BytesPerScanLine ModeAttributes + 16;: dw 0; Octets par "scanline" mot
%define XResolution ModeAttributes + 18;: dw 0; Résolution horizontale
%define YResolution ModeAttributes + 20;: dw 0; Résolution vertical
;XCharSize: db 0; Largeur d'un caractère
;YCharSize: db 0; Hauteur d'un caractère
;NumberOfPlanes ModeAttributes + 24;: db 0; Nombre de plans mémoire
%define BitsPerPixel ModeAttributes + 25;: db 0; Bits par pixel
;NumberOfBanks: db 0; Nombre de banques de style CGA
;MemoryModel: db 0; Type de modèle mémoire
;BankSize: db 0; Taille des banques de style CGA
;NumberOfImagePages: db 0; Nombre de pages image
;res1: db 0; Reservé
;RedMaskSize: db 0; Taille du masque rouge en couleur directe
;RedFieldPosition: db 0; Position du bit faible du masque rouge
;GreenMaskSize: db 0; Taille du masque vert en couleur directe
;GreenFieldPosition: db 0; Position du bit faible du masque vert
;BlueMaskSize: db 0; Taille du masque bleu en couleur directe
;BlueFieldPosition: db 0; Position du bit faible du masque bleu
;RsvdMaskSize: db 0; Taille du masque réservé en couleur directe
;RsvdFieldPosition: db 0;  Position du bit faible du masque réservé
;DirectColorModeInfo: db 0; Attributs du mode de couleur directe
;res2: times 216 db 0; Complément à 256 octets, taille du bloc

	jmp 0x07C0:debut ; On est chargé dans le segment 0x07C0
debut:
	; Met les segments utiles au segment de code courant
	mov ax, cs
	mov ds, ax
	mov es, ax

	;; Infos pilote VESA
	mov ax, 0x4F00 ; demande infos sur le pilote VESA VBE
	mov di, VESASignature
	int 10h
	cmp ax, 0x4F ; Si AL <> 0x4F, on n'a pas de VESA, donc fin. Si AH <> O, erreur, donc fin.
	jne fin

	;;Lecture des modes pour choisir le plus grand
	mov si, VideoModePtr ; pointeur vers la liste des modes supportés
	lodsw ; on charge l'adresse d'offset dans ax
	mov cx, ax ; cx contient l'adresse d'offset
	lodsw ; on charge l'adresse de segment dans ax
	mov si, cx ; si pointe sur le premier mode supporté
	mov dx, ax ; dx contient l'adresse de segment
lit_mode_suivant:
	push ds
		mov ds, dx ; ds contient l'adresse de segment de la liste des modes
		lodsw ;charge dans ax le mode
	pop ds
	cmp ax, 0xFFFF ; Fin de la liste
	je arret_modes
	mov cx, ax
	mov ax, 0x4F01 ; demande infos sur le mode VESA
	mov di, ModeAttributes
	int 0x10
	cmp ax, 0x4F ; Si AL <> 0x4F, la fonction n'est pas supportée, on se contentera du VGA. Si AH <> O, erreur, pareil.
	jne lit_mode_suivant
	test word [ModeAttributes], 0xF
	jz lit_mode_suivant
	push dx
		mov ax, [XResolution]
		shr ax, 5
		push ax
			mov ax, [YResolution]
			shr ax, 3
			push ax
				mov al, [BitsPerPixel]
				xor ah, ah
				shr ax, 3
			pop bx
			mul bx
		pop bx
		mul bx
	pop dx
	cmp ax, [maxResol]
	jb lit_mode_suivant
	mov [maxResol], ax
	mov [mode_souhaite], cx
    jmp lit_mode_suivant
arret_modes:
	mov cx, [mode_souhaite] ; On s'enquiert du mode souhaité
    mov ax, 0x4F01 ; demande infos sur le mode VESA
	mov di, ModeAttributes
    int 0x10

    mov ax, [WinASegment]
    or ax, ax ; on teste l'adresse du segment de la fenêtre. Si elle est nulle, on passe en mode 0x13
    jnz adresse_OK
adresse_mode_13h:
    mov word [mode_souhaite], 0x0013 ; infos du mode 0x13, le mode VGA
    mov word [WinASegment], 0xA000
    mov word [YResolution], 200
    mov word [XResolution], 320
adresse_OK:
	mov ax, 0x4F02
	mov bx, [mode_souhaite]
	int 0x10 ; Changement de mode vidéo

initialise_disque: ; Initialise le lecteur de disque
	xor ax, ax
	int 0x13
	jc initialise_disque; En cas d'erreur on recommence (sinon, de toute façon, on ne peut rien faire)

lire:
	mov ax, 0x1000 ; ES:BX = 1000:0000
	xor bx, bx
	mov es, ax
	mov ah, 2 ; Fonction 0x02 : chargement mémoire
	mov al, 6 ; On s'arrête au secteur n° 6
	xor ch, ch ; Premier cylindre (n° 0)
	mov cl, 2 ; Premier secteur (porte le n° 2, le n° 1, on est dedans, et le n° 0 n'existe pas)
	; Ca fait donc 5 secteurs
	xor dh, dh ; Tête de lecture n° 0
	; Toujours pas d'identifiant de disque, c'est toujours le même.
	int 0x13 ; Lit !
	jc lire ; En cas d'erreur, on recommence
	mov si, VESASignature
;	mov si, sautNoyau ; Un petit message pour rassurer les troupes.
;	call affiche_chaine
	jmp 0x1000:0000 ; Et on donne la main au programme que nous venons de charger

fin:
	jmp $

affiche_chaine:
	push ax
	push bx
	push cx
	push dx
	xor bh, bh; RAZ de bh, qui stocke la page d'affichage
	mov ah, 0x03
	int 0x10; appel de l'interruption BIOS qui donne la position du curseur, stockée dans dx
	mov cx, 1; nombre de fois où l'on va afficher un caractère
.affiche_suivant:
	lodsb
	or al, al;on compare al à zéro pour s'arrêter
	jz .fin_affiche_suivant
	cmp al, 13
	je .nouvelle_ligne
	mov ah, 0x0A;on affiche le caractère courant cx fois
	int 0x10
	inc dl; on passe à la colonne suivante pour la position du curseur
	cmp dl, 80
	jne .positionne_curseur
.nouvelle_ligne:
	inc dh; on passe à la ligne suivante
	xor dl, dl; colonne 0
.positionne_curseur:
	mov ah, 0x02;on positionne le curseur
	int 0x10
	jmp .affiche_suivant
.fin_affiche_suivant:
	pop dx
	pop cx
	pop bx
	pop ax
	ret
;fin de affiche_chaine

sautNoyau: db 'Saut au noyau', 13, 0
mode_souhaite: dw 0x0013
maxResol: dw 0
times 510-($-$$) db 0
dw 0xAA55
