; Exemple de secteur de boot (disquette) ; Auteur : Benoit Papillault ; Creation: Juin 1997 ; Derniere modification: Samedi 5 Juillet 1997 STACK_SIZE equ 100d ; au moins 53 pour que les interruptions ; du BIOS se deroule corectement SEGMENT_INITIAL equ 7c0h ; la valeur de CS lorsque ce code est execute ; par le BIOS ou le MBR du disque ; Pour debugger sous DOS avec Turbo-Debuggeur ; SEGMENT_INITIAL equ cs ; lorsque le pc boote, le premier secteur de la disquette est charge en ; memoire a l'adresse 0:7c00h, lorsque l'execution commence, on a: ; CS=0000h et IP=7c00h bios segment at 0ffffh org 0 bios_reboot: bios ends bios_data segment at 40h org 72h bios_flag dw ? bios_data ends ; on cree un segment data avec "at 0h" pour que TASM comprenne bien ; que le segment n'est pas initialise et que donc il ne doit pas ; lui reserve de place (on a que 512 octets [et encore!], on ne ; peut pas se permettre de gaspiller, donc on utilise un truc pas ; beau). On utilisera ce segment comme s'il s'agissait de _TEXT ; (meme si TASM ne veut pas!) _DATA segment at 0h org 200h ; permet de "mettre" les donnes non initialisee ; a la suite du premier secteur en memoire db STACK_SIZE dup (?) tos: sav_ax dw ? sav_ss dw ? sav_sp dw ? sav_si dw ? sav_ds dw ? _DATA ends _TEXT segment org 0h assume cs:_TEXT,ds:_DATA ; avec de tels assume, on peut faire a peu pres ce qui nous convient ; attention cependant a eviter des instructions mov mavar,ax ; avec mavar dans ce segment car un CS: sera genere (et encore un ; octets de gache) start: jmp short debut ; debut doit se trouver a l'offset 3eh ; sinon MS-DOS refuse de lire la disquette nop org 03h db 'MSDOS5.0' dw 200h db 1h dw 1h ; 10h db 2h dw 0e0h dw 0b40h db 0f0h dw 9h dw 12h dw 2h dw 0h dw ? ; 20h dd 0h db 0h db 0h db 29h ; signature db 'PAPI' ; serial number db 'DISK16 ' db 'FAT12 ' org 40h debut: ; on sauve DS et AX pour plus tard (en esperant que l'on puise mettre ; quatre octets dans la pile actuelle push ds push ax ; on initialise DS mov ax,SEGMENT_INITIAL mov ds,ax ; on sauvegarde quelques registres dans une pile inconnue pop sav_ax pop sav_ds mov sav_ss,ss mov sav_sp,sp mov sav_si,si ; on mets en place notre pile cli mov ss,ax mov sp,offset tos sti mov si,offset r_ax call prints mov ax,sav_ax call print_ax mov si,offset r_bx call prints mov ax,bx call print_ax mov si,offset r_cx call prints mov ax,cx call print_ax mov si,offset r_dx call prints mov ax,dx call print_ax mov si,offset r_sp call prints mov ax,sav_sp call print_ax mov si,offset r_bp call prints mov ax,bp call print_ax mov si,offset r_si call prints mov ax,sav_si call print_ax mov si,offset r_di call prints mov ax,di call print_ax mov si,offset r_ds call prints mov ax,sav_ds call print_ax mov si,offset r_es call prints mov ax,es call print_ax mov si,offset r_ss call prints mov ax,sav_ss call print_ax mov si,offset r_cs call prints mov ax,cs call print_ax mov si,offset r_ip call prints call get_ip retour_get_ip: sub ax,retour_get_ip - start call print_ax ; un retour chariot mov al,13 call printc mov al,10 call printc mov si,offset Mess call prints mov ah,0 int 16h mov al,7 call printc ; mov dl,0 ; int 19h ; Pour eviter le test de la memoire, on met 40:72 a 1234 mov ax,seg bios_data mov es,ax assume es:bios_data mov bios_flag,1234h ; cold boot ??? !!! jmp far ptr bios_reboot ; mov ax,4c00h ; int 21h boucle_infinie: xor ax,ax int 16h mov al,'.' call printc jmp short boucle_infinie ; imprime une chaine (termine par zero) dans DS:SI prints: ; cld ; lodsb ; equivalent de mov al,ds:si et inc si mais en moins d'octets mov al,[ds:si] inc si cmp al,0 je short fin_prints call printc jmp short prints fin_prints: ret ; retourne la valeur de IP (adresse de retour de la fonction) dans AX ; modifie le registre BP get_ip: mov bp,sp mov ax,[bp] ret ; imprime la valeur en hexadecimal des 4 bits de poids faibles de AL ; aucune modification des registres print_a4: push ax and al,0fh ; AL = le premier chiffre cmp al,10 jl short print_a4_ok add al,'A'-'0'-10 print_a4_ok: add al,'0' call printc pop ax ret ; fin de print_a4 ; imprime la valeur hexa de AX ; aucune modification des registres print_ax: push cx mov cl,4 rol ax,cl call print_a4 rol ax,cl call print_a4 rol ax,cl call print_a4 rol ax,cl call print_a4 pop cx ret ; affiche le caractere AL ; la position du curseur est mise a jour ; on utilise la fonction 0eh de l'interruption 10h ; avec AH=0eh, AL=caractere, BH=page (ici 0) et ; BL=couleur d'ecriture (ici 7=blanc) printc: push ax push bx mov ah,0eh mov bx,7 int 10h pop bx pop ax ret ; debut de la zone de donnees propres au programme Mess db 'Chargement du boot...',13,10,7,0 r_ax db 'AX=',0 r_bx db ' BX=',0 r_cx db ' CX=',0 r_dx db ' DX=',0 r_sp db ' SP=',0 r_bp db ' BP=',0 r_si db ' SI=',0 r_di db ' DI=',0 ; ligne suivante r_ds db 13,10,'DS=',0 r_es db ' ES=',0 r_ss db ' SS=',0 r_cs db ' CS=',0 r_ip db ' IP=',0 end: ; pour marquer la fin du code et des donnes statiques org 1feh db 55h,0aah _TEXT ends end start