bon, voici un exemple simple pour démarrer le PC en mode protégé.
évidement, ce code ci n'est pas optimisé pour la taille, le record à ma connaissance étant de même pas 40 octets.
non, ici, il s'agit du code minimal compréhensible par le plus de codeurs possible.
avec les commentaires (en french please) et tout ce qu'il faut pour montrer comment que ça marche ce truc là.
regardez bien, le petit oiseau va sortir
donc, comme déjà indiqué dans les commentaires, ce code, il se contente de vraiment très peu de choses.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;demarrage et mode protégé ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 7c00h ; l'emplacement où sera chargé et exécuté ce programme boot: ; amorçage = 7c00h (org) cli ; désactiver les interruptions lgdt fword[cs:gdt.r] ; charger la gdt depuis [cs:gdt.taille], pseudo descripteur de 6 octets mov eax,cr0 ; équivalent à "or cr0,1" or al,1 ; commuter le CPU en mode protégé mov cr0,eax ; mode protégé activé jmp gdt.code:activé ; équivalent à "mov cs,gdt.code" + "mov eip,activé" activé: ; la première instruction à exécuter après l'activation du mode protégé use32 ; le code ci dessous est encodé pour le mode 32 bits mov ax,gdt.données ; le registre "ax" pointe vers le contenu de gdt.data mov ds,ax ; le sélecteur "ds" charge le descripteur de segment gdt.data mov ah,74h ; couleur du texte mov esi,bonjour ; pointer vers le message à afficher mov ecx,0b8000h ; pointer vers la mémoire vidéo mode texte mov edi,0 ; pointer sur la première cellule de la mémoire vidéo, en haut à gauche @@: ;boucle d'affichage du texte mov al,[cs:esi] ; charger un caractère dans al or al,al ; caractère null, al=0? je @f ; si oui, sortie mov [ecx+edi*2],ax ; afficher le caractère en rouge sur fond gris, en haut à gauche inc esi ; incrémenter les pointeurs inc edi ; ... jmp @b ;goto boucle d'affichage du texte @@: ; sortie hlt ; mettre le CPU en pause, comme cela, il consomme peu d'énergie jmp $ ; reboucler infiniment ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bonjour: ; message à afficher db 'bonjour',0 ; bonjour align 8 ; aligner la prochaine instruction sur une adresse multiple de 8 octets. gdt: dw 0 ; aligner la partie 32 bits du pseudo descripteur sur une adresse .r dw @f-gdt-1 ; partie 16 bits du pseudo descripteur, taille de la gdt en octets .linear dd gdt ; partie 32 bits du pseudo descripteur, adresse de base linéaire .code=$-gdt ; première entrée dans la gdt (8*1) dw 0ffffh,0 ; 4 giga octets, base à l'adresse linéaire 0 db 0,10011010b,11001111b,0 ; granularité = 4 kilo octets, segment de code, privilège 0, exécutable .données=$-gdt ; second entry in gdt (8*2) dw 0ffffh,0 ; 4Gbytes, start at linear 0 db 0,10010010b,11001111b,0 ; granularity = 4Kbytes, data segment, ring 0, read/write, present,etc... @@: ; used for gdt.size calculation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; libre = 510-(remplissage-$$) ; define "free" bytes count remplissage rb libre ; reserve "free" bytes to make line below at offset 510 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; dw 0aa55h ; magic number boot mark, used by bios to test if valid boot sector ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; d1='0'+libre shr 8 and 0fh ; d2='0'+libre shr 4 and 0fh ; d3='0'+libre and 0fh ; if d1>'9' ; d1=d1+7 ; end if ; ; if d2>'9' ; d2=d2+7 ; end if ; ; if d3>'9' ; d3=d3+7 ; end if ; ; display d1,d2,d3,'h ' ; display 'libre bytes',13,10 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; d1='0'+(510-libre)shr 8 and 0fh ; d2='0'+(510-libre)shr 4 and 0fh ; d3='0'+(510-libre)and 0fh ; if d1>'9' ; d1=d1+7 ; end if ; ; if d2>'9' ; d2=d2+7 ; end if ; ; if d3>'9' ; d3=d3+7 ; end if ; ; display d1,d2,d3,'h ' ; display 'used bytes',13,10 ; ;segment_descriptor: ;.limitl =0 ;.basel =2 ;.basem =4 ;.field1 =5 ;.type =0fh ;.s =10h ;.dpl =60h ;.p =80h ;.field2 =6 ;.limith =0fh ;.avl =10h ;.db =40h ;.g =80h ;.baseh =7
il désactive les interruptions, comme ça, pas de problème, pas besoin de définir la mystérieuse table de descripteurs d'interruptions (IDT).
suite à ça, le registre GDTR est chargé avec la valeur du pseudo descripteur défini plus loin en tant que gdt.r. notez que ce pseudo descripteur (c'est le nom officiel donné par intel) mesure 48 bits, et est aligné sur 8 octets + 2, car la première partie mesure 16 bits, et la seconde 32 bits. c'est comme ça, ne cherchez pas, intel à dit de faire comme ça, il faut faire comme ça. sauf si on veut ralentir l'instruction LGDT de 2 cycles. ce qui est acceptable mais non désiré, surtout quand on code en assembleur.
bon, la suite:
une fois le registre GDTR chargé avec le pseudo descripteur 48 bits gdt.r, il faut activer le mode protégé.
chose faite en positionnant le bit PE (bit 0) du registre CR0, à 1.
pour ça, on lit une première fois le registre, en le copiant dans eax, ou ailleurs, peu importe.
puis hop, or eax,1, et le bit est mis à 1. magique!!!! et on copie le contenu de eax dans cr0.
le tour est joué, le CPU est en mode protégé, mais il reste une chose primordiale à faire.
charger la partie invisible de CS avec le bon descripteur.
pour ça, un jmp far (saut éloigné en français) vers l'adresse désirée, ici, gdt.cs:activé, et nous voilà enfin en mode protégé, pour de vrai.
le reste, c'est de l'initialisation de registres, on charge le segment de données avec le bon descripteur.
on pointe vers la mémoire vidéo en mode texte.
puis on écrit "bonjour", parce qu'on est polit.
et voilà.
si vous voulez tester ce code, de multiples moyens s'offrent à vous.
vous devez copier le fichier compilé sur le premier secteur du disque de démarrage (disquette, disque dur, clé usb, émulation sur cdrom, image de disque, peu importe) et lancer la machine (virtuelle ou réelle, peu importe).
magique, il s'affiche le message bonjour en haut à gauche de l'écran. c'est joli, ça marche.
et on va passer à la suite, car on s'arrête pas à ça.
au passage, notez que je n'ai pas traduit les commentaires à la fin, j'estime que vous étant mis à l'assembleur, vous n'avez pas peur de trois mots en anglais, en plus, c'est de l'anglais fastoche, écrit pas un français (moi).
pour la macro à la fin, il ne s'agit que d'un message que le compilateur FASM fourni à la compilation, pour dire combien il reste d'octets, et combien d'octets sont utilisés. donc, normalement, avec ce code, vous voyez ça:
19Eh libre bytes
060h used bytes
ce qui veut dire que le code n'utilise que 96 octets (c'est énorme) et que vous avez encore 414 octets dans le secteur de boot pour vous amuser. vérification:
un secteur = 512 octets.
le dernier word (offset 510) est utilisé pour le mot magique. 0AA55h
il reste bien 510 octets pour travailler.
bien évidement, il n'y à pas de table de partition, ça sert à rien ce genre de chose, surtout quand on n'aime pas windows et linux.
to be continued
Partager