%define	BASE	0x7000		; 0x07000:0x0 = 0x70000
%define KSIZE	5
%define BOOT_SEG 0x07c0

;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
%define FlatMemory ModeAttributes + 40
;res2: times 216 db 0; Complément à 256 octets, taille du bloc

BITS 	16
org 	0x0000 ; Adresse de début bootloader

;; Initialisation des segments en 0x07C0
	mov 	ax, 	BOOT_SEG
	mov 	ds, 	ax
	mov 	es, 	ax
	mov 	ax, 	0x8000	; pile en 0xFFFF
	mov 	ss, 	ax
	mov 	sp, 	0xf000

;; Affiche un message
	mov 	si, 	msgDebut
	call afficher

;; Charge le noyau
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, 	BASE 	; ES:BX = BASE:0000
	mov 	es, 	ax
	xor 	bx, 	bx
	mov 	ah, 	2 		; Fonction 0x02 : chargement mémoire
	mov 	al, 	KSIZE 	; On lit KSIZE secteurs
	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)
	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

	;; Infos pilote VESA
	mov ax, BOOT_SEG
	mov es, ax
	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
	cmp word [ModeAttributes], 0x9B;
	jb lit_mode_suivant
	push dx
		mov ax, [XResolution]
		shr ax, 5
		push ax
			mov ax, [YResolution]
			shr ax, 3
			push ax
				mov al, [BitsPerPixel]
				cmp al, 32
				jne lit_mode_suivant
				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, [FlatMemory]; bits de poids faible
	mov [gdt_flb + 2], ax
	mov ax, [FlatMemory + 2]; bits de poids fort
	mov [gdt_flb + 4], al
	mov [gdt_flb + 7], ah
	
	mov ax, 0x4F02
	mov bx, [mode_souhaite]
	or bx, 0100000000000000b ; Le bit n°14 à 1 demande l'utilisation de la mémoire à plat.
	int 0x10 ; Changement de mode vidéo
	
;; Passe en mode protégé
	cli
	lgdt 	[pointeurGDT]	; charge la gdt
	mov 	eax,	cr0
	or 		ax,		1
	mov 	cr0, 	eax		; PE mis a 1 (CR0)

	jmp next
next:
	mov 	ax, 	gdt_ds - gdt	; offset du descripteur du segment de données
	mov 	ds, 	ax
	mov 	fs, 	ax
	mov 	gs, 	ax
	mov 	es, 	ax
	mov 	ss, 	ax
	mov 	esp,	0x9F000	

	mov esi, VESASignature + BOOT_SEG << 4
	jmp dword 0x8:BASE << 4; réinitialise le segment de code

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Synopsis: Affiche une chaîne de caractères se terminant par NULL	;;
;; Entrée:   DS:SI -> pointe sur la chaîne à afficher				;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
afficher:
	push	ax
	push	bx
.debut:
	lodsb			; ds:si -> al
	cmp 	al, 0	; fin chaîne ?
	jz .fin
	mov 	ah, 0x0E	; appel au service 0x0e, int 0x10 du BIOS
	mov 	bx, 0x07	; bx -> attribut, al -> caractère ASCII
	int 0x10
	jmp .debut

.fin:
	pop bx
	pop ax
	ret

fin:
	jmp $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
msgDebut	db	"Chargement du kernel", 13, 10, 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdt:
	db 0x00, 0x00, 0x00, 0x00, 0x00, 00000000b, 00000000b, 0x00
gdt_cs:
	db 0xFF, 0xFF, 0x00, 0x00, 0x00, 10011011b, 11011111b, 0x00
gdt_ds:
	db 0xFF, 0xFF, 0x00, 0x00, 0x00, 10010011b, 11011111b, 0x00
gdt_flb:
	dw 0xFFFF, 0x0000
	db 0x00, 10010011b, 11011111b, 0xE0
gdtend:

pointeurGDT:
	dw	gdtend-gdt				; taille
	dd	(BOOT_SEG << 4) + gdt	; base

mode_souhaite: dw 0x0013
maxResol: dw 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rien jusqu'à 510
times 510-($-$$) db 0
dw 0xAA55
