2015-11-30 5 views
1

J'essaie de charger le numéro de secteur de [head = 0, cilinder (track) = 1, sector = 1] à partir de disquette en utilisant l'interruption du BIOS 13h, depuis mon chargeur de démarrage fat12. J'utilise le sous-programme read_sectors pour lire le secteur et le charger à es: bx.Le BIOS int 13h ne peut pas lire la première piste

Ce code fonctionne bien avec n'importe quel secteur de la première piste, mais il lit juste 0s de n'importe quel secteur des autres pistes, alors que ces secteurs sont réellement peuplés. Avec le secteur 18, par exemple, cx est 0x0041, ce qui est juste. Le problème est, l'interruption définit CF, en disant qu'il y a une erreur. Il définit également ah (code de retour) à 1, et al (secteurs lire) à 1.

Ceci est le fichier complet bootloader .asm

bits 16 
org 0 

start: jmp load 

nop 
OEM:     DB "ptiaOS " 
bytesPerSector:  DW 512 
sectorsPerCluster: DB 1 
reservedSectors: DW 1 
numberOfFATs:  DB 2 
rootEntries:  DW 224 
totalSectors:  DW 2880 
media:    DB 0xf8 
sectorsPerFAT:  DW 9 
sectorsPerTrack: DW 18 
headsPerCylinder: DW 2 
hiddenSectors:  DD 0 
totalSectorsBig:  DD 0 
driveNumber:   DB 0 
unused:   DB 0 
extBootSignature: DB 0x29 
serialNumber:   DD 0xa0a1a2a3 
volumeLabel:   DB "PTIAOS FLP " 
fileSystem:    DB "FAT12 " 

load: 
    ;The bootloader is loaded at the address 0x7C00 and is 0x200 (512) bytes long 
    cli 
    mov ax, 0x07C0 ; setup registers to point to our segment 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 
    sti 

    mov si, hello_string 
    call prints 

    mov si, try_string 
    call prints 

    mov ax, 18 
    call lba_to_chs 

    mov al, 2 
    mov bx, 0x200 
    call read_sectors 

    mov si, success_string 
    call prints 

    mov si, 0x200 
    call prints 

    cli 
    hlt ;halt 



;--------DATA-------- 
hello_string db `Hi, bootloader of ptiaOS here\n\r`, 0 
success_string db `Successfully loaded from floppy\n\r`, 0 
try_string db `Loading more data from floppy...\n\r`, 0 
;CHS position of the sector to read 
sector_number db 0 ;1 is the first (they're 18 per track) 
cilinder_number db 0 ;track number: 0 is the first (they're 80 per side) 
head_number db 0 ;0 is the first (the're 2) 

;---SOTTOPROGRAMMI--- 
;print a 0-terminated string pointed by ds:si 
prints: 
    mov ah, 0x0E ;dico all'interrupt del BIOS video di eseguire la funzione di stampa [al: carattere, bh: pagina] 
    .prints_printchar: 
    lodsb ;al = *(si++) 
    cmp al, 0 
    je .prints_end ;if(al == 0) goto print_string_end 
     int 0x10 ;chiamo l'interrupt di i/o dello schermo, con ah = 0x0E per stampare il carattere in al 
     jmp .prints_printchar 
    .prints_end: 
    ret 


;Read sectors from floppy at the address specified by CHS variables, and load them in es:bx 
read_sectors: 
    mov ah, 0x02 ;function 0x02, interrupt 0x13: read sectors 
    ;al (the number of sectors to read), es:bx (destination) are set as arguments 
    xor cx, cx 
    mov cl, [cylinder_number] 
    shl cl, 6 
    or cl, [sector_number] 
    mov dh, [head_number] 
    mov dl, 0 
    int 0x13 
    jnc .sectors_read_successfully ;CF = 0 if no errors, 1 otherwise 
    ;if errors occured, try to reset floppy 
    .flp_reset: 
    mov ah, 0 ;function 0, interrupt 0x13: reset disk 
    mov dl, 0 ;disk to reset: 0=floppy 
    int 0x13 
    jc .flp_reset ;CF = 0 if no errors, 1 otherwise 
    jmp read_sectors 
    .sectors_read_successfully: 
    ret 

lba_to_chs: 
    mov cx, ax 

    mov bl, [sectorsPerTrack] 
    div bl 
    inc ah ;ah = lba % 18 + 1 
    mov byte [sector_number], ah 

    mov ax, cx 
    mov bl, [sectorsPerTrack] 
    div bl ;al = lba/18 
    cbw ;ax = lba/18 
    mov bl, [headsPerCylinder] 
    div bl ;al = lba/18/2; ah = lba/18 % 2 
    mov byte [cilinder_number], ah 
    mov byte [head_number], al 

    ret 

times 510-($-$$) db 0 
dw 0xAA55 

Je courais ce code sur qemu, à partir d'Ubuntu, et la compiler avec

nasm -f bin -o ptiaos.bin ptiaboot.asm 
nasm -f bin -o BSTAGE2.SYS blstage2.asm 

mkdir floppy 
dd status=noxfer conv=notrunc if=ptiaos.bin of=ptiaos.flp 
sudo mount -o loop ptiaos.flp floppy 
sudo cp BSTAGE2.SYS floppy 

sleep 0.1 
sudo umount floppy 
rm BSTAGE2.SYS 
rm ptiaos.bin 
rmdir floppy 
+0

Vous devez calculer l'adresse correcte de CHS pour la géométrie l'appareil que vous lisez que je ne vois pas dans votre code. Ce n'est pas trivial. J'ai trouvé [cette page OSdev] (http://wiki.osdev.org/ATA_in_x86_RealMode_%28BIOS%29) utile pour [mon implémentation] (https://github.com/neonics/qure/blob/master/bootloader/sector1 .s # L1679). – Kenney

+0

En fait, j'utilise un sous-programme basé sur la page OSdev pour calculer l'adresse CHS. Je l'ai juste omis de la question, car il semble fonctionner correctement, et a passé l'adresse chs directement à la fonction read_sectors. L'adresse [head = 0, cilinder (track) = 1, sector = 1] est en fait l'adresse LBA (indexée 0) 18. Si vous pensez que j'ai besoin d'afficher la sous-routine ici, je l'afficherai. Merci d'avoir répondu si rapidement. – ptia

+0

De rien. Je vérifiais simplement - d'après mon expérience, le problème réside généralement dans le calcul du CHS, ou dans l'hypothèse d'un mauvais nombre de cylindres/têtes/pistes pour le lecteur. Vous avez donc des difficultés à lire l'adresse LBA 19 et suivantes: avez-vous vérifié manuellement que le LBA 19 est converti au bon CHS? Si c'est le cas, il n'est pas nécessaire d'afficher le calcul CHS. Encore une chose: les données sont lues dans 'es: bx' et je ne vois pas comment' bx' est initialisé. – Kenney

Répondre

2

Je vais suggérer un correctif, mais avec une hypothèse. Il semble que lba_to_chs est conçu pour fonctionner avec des tailles de disque plus petites où le nombre de cylindres ne dépasse pas 0xff (255). C'est très bien pour les tailles de disquettes conventionnelles puisque le nombre de cylindres sera généralement beaucoup moins que cela.

tout d'abord il y a un bogue dans ce code:

mov ax, cx 
    mov bl, [sectorsPerTrack] 
    div bl ;al = lba/18 
    cbw ;ax = lba/18 
    mov bl, [headsPerCylinder] 
    div bl ;al = lba/18/2; ah = lba/18 % 2 
    mov byte [cilinder_number], ah 
    mov byte [head_number], al 

Dans la division finale AL doit contenir le nombre de cylindres et AH doit contenir le numéro de tête. Dans votre code, vous les avez inversés. Les deux dernières lignes doivent avoir lu:

mov byte [cilinder_number], al 
    mov byte [head_number], ah 

Compte tenu de l'hypothèse qui a été fait sur les bouteilles ne dépassant pas 255, on peut modifier le code de read_sector un peu. INT 13h AH=02h nécessite le nombre de cylindres et le numéro de secteur à placer dans CX de cette manière:

CX =  ---CH--- ---CL--- 
cylinder :98 
sector :

Ils donnent également cette équation pour la manipulation de bits:

CX: = ((cylindre et 255) shl 8) ou ((cylindre et 768) shr 2) ou secteur;

Étant donné que nos cylindres ne dépassera pas 255 l'équation se réduit jusqu'à:

CX: = ((cylindre et 255) SHL 8) ou d'un secteur;

Ceci est le même que le stockage cylindre simplement en CH et le secteur dans CL.Ainsi, le code avait pour la mise en CX (CL et CH) qui apparaît comme:

mov ah, 0x02 ;function 0x02, interrupt 0x13: read sectors 
    ;al (the number of sectors to read), es:bx (destination) are set as arguments 
    xor cx, cx 
    mov cl, [cylinder_number] 
    shl cl, 6 
    or cl, [sector_number] 
    mov dh, [head_number] 
    mov dl, 0 
    int 0x13 

ressemblerait à quelque chose comme:

mov ah, 0x02 ;function 0x02, interrupt 0x13: read sectors 
    ;al (the number of sectors to read), es:bx (destination) are set as arguments mov ch, [cilinder_number] 
    mov ch, [cilinder_number] 
    mov cl, [sector_number] 
    mov dl, 0 
    mov dh, [head_number] 
    int 0x13 

Le code ci-dessus a un autre défaut, et c'est le DL le registre est mis à 0. C'est le numéro de lecteur pour lire le secteur. Cela doit être défini sur le numéro de lecteur que le BIOS passe dans DL à notre chargeur de démarrage lorsqu'il passe à l'adresse de mémoire 0x07c00. Nous devrions enregistrer cette valeur au démarrage, puis le copier à DL lorsque nous lisons un secteur. Cela nous permet de démarrer à partir d'un lecteur qui n'a pas été la première disquette de démarrage (numéro de disque 0x00).

Le code peut être modifié par l'ajout d'un Lecteur_démarrage variable à votre zone de données:

boot_drive db 0 

Après l'initialisation des registres de segment enregistrer le DL (disque de démarrage) passe à notre chargeur de démarrage avec:

mov [boot_drive], dl 

Et puis dans load_sector changement:

mov dl, 0 

à:

mov dl, [boot_drive] 

Le code final après toutes les suggestions des corrections et des changements pourraient regarder au-dessus quelque chose comme:

bits 16 
org 0 

GLOBAL main 
main: 
start: jmp load 

nop 
OEM:     DB "ptiaOS " 
bytesPerSector:  DW 512 
sectorsPerCluster: DB 1 
reservedSectors: DW 1 
numberOfFATs:  DB 2 
rootEntries:  DW 224 
totalSectors:  DW 2880 
media:    DB 0xf8 
sectorsPerFAT:  DW 9 
sectorsPerTrack: DW 18 
headsPerCylinder: DW 2 
hiddenSectors:  DD 0 
totalSectorsBig:  DD 0 
driveNumber:   DB 0 
unused:   DB 0 
extBootSignature: DB 0x29 
serialNumber:   DD 0xa0a1a2a3 
volumeLabel:   DB "PTIAOS FLP " 
fileSystem:    DB "FAT12 " 

load: 
    ;The bootloader is loaded at the address 0x7C00 and is 0x200 (512) bytes long 
    cli 
    mov ax, 0x07C0 ; setup registers to point to our segment 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 
    sti 
    mov [boot_drive], dl 

    mov si, hello_string 
    call prints 

    mov si, try_string 
    call prints 

    mov ax, 18 
    call lba_to_chs 

    mov al, 1 
    mov bx, 0x200 
    call read_sectors 

    mov si, success_string 
    call prints 

    mov si, 0x200 
    call prints 

    cli 
    hlt ;halt 



;--------DATA-------- 
boot_drive db 0 
hello_string db `Hi, bootloader of ptiaOS here\n\r`, 0 
success_string db `Successfully loaded from floppy\n\r`, 0 
try_string db `Loading more data from floppy...\n\r`, 0 
;CHS position of the sector to read 
sector_number db 0 ;1 is the first (they're 18 per track) 
cilinder_number db 0 ;track number: 0 is the first (they're 80 per side) 
head_number db 0 ;0 is the first (the're 2) 

;---SOTTOPROGRAMMI--- 
;print a 0-terminated string pointed by ds:si 
prints: 
    mov ah, 0x0E ;dico all'interrupt del BIOS video di eseguire la funzione di stampa [al: carattere, bh: pagina] 
    .prints_printchar: 
    lodsb ;al = *(si++) 
    cmp al, 0 
    je .prints_end ;if(al == 0) goto print_string_end 
     int 0x10 ;chiamo l'interrupt di i/o dello schermo, con ah = 0x0E per stampare il carattere in al 
     jmp .prints_printchar 
    .prints_end: 
    ret 
;Read sectors from floppy at the address specified by CHS variables, and load them in es:bx 
read_sectors: 
    mov ah, 0x02 ;function 0x02, interrupt 0x13: read sectors 
    ;al (the number of sectors to read), es:bx (destination) are set as arguments mov ch, [cilinder_number] 
    mov ch, [cilinder_number] 
    mov cl, [sector_number] 
    mov dl, [boot_drive] 
    mov dh, [head_number] 
    int 0x13 
    jnc .sectors_read_successfully ;CF = 0 if no errors, 1 otherwise 
    ;if errors occured, try to reset floppy 
    .flp_reset: 
    mov ah, 0 ;function 0, interrupt 0x13: reset disk 
    mov dl, 0 ;disk to reset: 0=floppy 
    int 0x13 
    jc .flp_reset ;CF = 0 if no errors, 1 otherwise 
    jmp read_sectors 
    .sectors_read_successfully: 
    ret 

lba_to_chs: 
    mov cx, ax 

    mov bl, [sectorsPerTrack] 
    div bl 
    inc ah ;ah = lba % 18 + 1 
    mov byte [sector_number], ah 

    mov ax, cx 
    mov bl, [sectorsPerTrack] 
    div bl ;al = lba/18 
    cbw ;ax = lba/18 
    mov bl, [headsPerCylinder] 
    div bl ;al = lba/18/2; ah = lba/18 % 2 
    mov byte [cilinder_number], al 
    mov byte [head_number], ah 

    ret 

times 510-($-$$) db 0 
dw 0xAA55