|
Candidat au titre de Membre du Club
Inscription : mars 2006 Messages : 100 Détails du profil  Informations forums : Inscription : mars 2006 Messages : 100 Points : 12 Points : 12
|
Bootloader et Kernel, passage mode protégé ↔ réel
Bonjour à vous tous !
Me revoilà, et encore avec des problèmes (pour changer). Je me suis mis il y a plus ou moins 1 mois a l'assembleur et, comme tous débutant, on veut faire de grandes choses, comme coder un OS comme Windows (version -14 pour ma part :p). Je suis le tutoriel sur le cours de Pépin, très bien fait en plus, mais voilà, je suis arrivé au mode protégé. Donc, plus d'interruption et, pour le mode VESA, ça devient compliqué haha :p.
Pour le mode vesa, en recherchant, je suis tombé sur ce lien où une des personnes explique (en gros) comment utiliser le mode VESA 2.0 en mode protégé. Mais voilà, vu que je suis déjà en mode protégé, quelques soucis « subsistent » (pas sûr de l'écriture) et, donc, je me suis résolu à faire quelques tests en mode texte, plutôt que de faire le kikoolol. J'ai réussi à afficher un écran blanc sans en comprendre le fonctionnement. J'ai donc testé un total de 2 codes. Les deux sont assez légers ^^.
Voila le bootloader, il passe en mode protégé :
Code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| %define BASE 0x100 ; 0x0100:0x0 = 0x1000
%define KSIZE 50 ; nombre de secteurs a charger
[BITS 16]
[ORG 0x0]
jmp start
start:
;initialisation des segments en 0x07C0
mov ax, 0x07C0
mov ds, ax
mov es, ax
;Initialisation de la pile(F000h - 8000h) = 7000h
mov ax, 0x8000
mov ss, ax
mov sp, 0xF000
;On récupère l'unité de boot utilisée
;Disque dur? Disquette?
mov [bootdrv], dl
;charger le noyau
xor ax, ax
int 0x13
;On sauvegarde es
push es
;On récupère l'adresse du début du kernel
mov ax, BASE
mov es, ax
mov bx, 0
;On récupère la fonction et le nombre de secteurs à charger
mov ah, 2
mov al, KSIZE
;On indique les cylindres et à partir de quel secteur on charge
mov ch, 0
mov cl, 2
;On indique à partir de quelle tête et quelle unité de disque
mov dh, 0
mov dl, [bootdrv]
int 0x13
;On restaure es
pop es
;initialisation du pointeur sur la GDT
;Calcul de la limite de la GDT (fin - début)
mov ax, gdtend
mov bx, gdt
sub ax, bx
;On met la limite dans le premier champ de la gdt
mov word [gdtptr], ax
;Calcul de l'adresse linéaire de la GDT
;Mise à 0 des registres
; xor eax, eax
; xor ebx, ebx
; On récupère l'adresse de base 0x07C0
; mov ax, ds
; On "déplace d'une lettre vers gauche" l'adresse de base
; 0x07C0 -->> 0x7C00
; mov ecx, eax
; shl ecx, 4
; On Ajoute le pointeur de la gdt
; mov bx, gdt
; add ecx, ebx
; On écrit le pointeur dans le champ pointeur de la GDT
; mov dword [gdtptr + 2], ecx
mov eax, 0x7C00
add eax, gdt
mov dword [gdtptr + 2], eax
;passage en modep
cli ;Annule les interruptions
lgdt [gdtptr] ;charge la gdt
mov eax, cr0
or ax, 1
mov cr0, eax ;On met le bit de poids faible de CR0 a 1
;On vide le cache interne
jmp next
next:
;Et on réinitialise les segments
;Les segments de données
mov ax, 0x10
mov ds, ax
mov fs, ax
mov gs, ax
mov es, ax
mov ss, ax
mov esp, 0x9F000
;Réinitialise le segment de code et "jump" vers le kernel
jmp dword 0x8:0x1000
;Les Variables
;--------------------------------------------------------------------
bootdrv: db 0
;--------------------------------------------------------------------
gdt:;Pointeur sur le début du segment de la GDT
db 0, 0, 0, 0, 0, 0, 0, 0
;Déscripteur "NULL"
gdt_cs:
db 0xFF, 0xFF, 0x0, 0x0, 0x0, 10011011b, 11011111b, 0x0
;Descripteur de code
;La base est 0x0, la limite 0xFFFFF * 4096 ~= 4go
gdt_ds:
db 0xFF, 0xFF, 0x0, 0x0, 0x0, 10010011b, 11011111b, 0x0
;Descripteur de segment
;Idem
gdtend:;Pointeur sur la fin du segment de la GDT
;--------------------------------------------------------------------
gdtptr:
dw 0 ; limite
dd 0 ; base
;--------------------------------------------------------------------
;Bourrage de 0 pour arriver a 510 octets
times 510-($-$$) db 0
;On ajoute le mot 0x55AA a l'envers car intel = Little Endian
dw 0xAA55 |
Et voici le code du kernel :
Code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| [bits 32]
org 0x1000
jmp _start
_start:
;On réactive les interruptions et on repasse en mode réel
sti
mov eax, cr0
dec eax
mov cr0, eax
;On réinitialise les différents segments
mov ax, 0x100
mov es, ax
mov ds, ax
;Et on écrit le magnifique caractère 'B'
mov ax, 0x03
int 0x10
xor bx, bx
mov cx, 1
xor dx, dx
mov ax, 0x02
int 0x10
mov ax, 0x0A42
int 0x10
end: jmp end |
Ce code, comme vous vous en doutez, ne fonctionne évidemment pas, il ne me fait pas "rebooter" le PC comme des fois quand j'essaye d'écrire en dehors d'une zone allouée, mais il laisse l'écran noir, avec le petit curseur qui clignote en haut a gauche, pas très utile donc.
Je me suis dit que c'était dut au mode "32 bits", mais ma connaissance là-dedans peut s'apparenter à un petit trou noir.
J'en ai donc profité pour faire un petit bidouillage maison, qui fut tout de même plus convaincant.
Voici mon fichier kernel1 :
Code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [bits 32]
%define b2 0x0A00
org 0x1000
jmp _start
_start:
;On passe en mode réel
sti
mov eax, cr0
dec eax
mov cr0, eax
jmp b2:0 |
et kernel2
Code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| [bits 16]
[org 0x0]
jmp _start
_start:
mov ax, 0xA00
mov es, ax
mov ds, ax
;On initialise les segments et on affiche le caractère
mov ax, 0x03
int 0x10
xor bx, bx
mov cx, 1
xor dx, dx
mov ax, 0x02
int 0x10
mov ax, 0x0A42
int 0x10
end: jmp end |
Ce code fut plus convaincant, en effet. Il ne m'affiche pas le B, il ne faut pas rêver, mais m'affiche un "fond" cyan de la taille d'un caractère a la place du B.
Merci de votre aide.
|