Grevak
Grevak

Reputation: 543

Why does int 10h not work after reading sectors with int 13h?

I want to write a simple bootloader. However, after reading 2 sectors from disk my boot sector can't print strings with int 10h, ah=0Eh

It works before I call int 13h, ah=02h

My Code:

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org 0x7c00
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    xor     ax, ax
    mov     ds, ax
    mov     es, ax
    mov     ss, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     si, 0x7c00
    mov     di, 0x7a00
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x0000:(_continue - 0x200)

_continue:

; Reset boot disk (try it 3 times before error message is printed)
    mov     cx, 4
_reset:
    sub     cx, 1
    cmp     cx, 0
    je      _error
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13
    jc      _reset

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
    mov     cx, 4
_load:
    sub     cx, 1
    cmp     cx, 0
    je      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    mov     bx, 0x7c00
; IT STILL WORKS HERE <--------
    int     0x13
; IT DOESN'T WORK ANYMORE <--------
    jc      _load

    mov     si, error_msg
    call    print

; Jump to the second boot sector

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Fill the rest of the 512 bytes with 0, byte 510 and 511
; contains 0xaa55 (boot signature for BIOS)

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

I searched google to solve the problem but nobody else had this problem before.

I debugged with bochs and found out...

  1. that I can print something onto the screen by writing chars to b800:0000

  2. that the 2 sectors were read correctly. I dumped the memory at 0x7c00 with bochs and it shows the right values

  3. that my bootloader is not in an endless loop because debugging with bochs shows that it executes the instructions after reading the 2 sectors

I don't know how to solve this problem. Can anyone help me?

Upvotes: 2

Views: 547

Answers (1)

Michael Petch
Michael Petch

Reputation: 47573

TL;DR The primary problem with your code as @jester pointed out is that you used an org 0x7c00 which means all absolute references are relative to 0x7c00. When you copy to 0x7a00 the code you generated is still referencing 0x7c?? addresses. When you overwrite memory at 0x7c00 the references to labels like error_msg, BS_DriveNum are to data that has been replaces, and it fails.


There are a few ways to fix the issue:

  1. The simplest fix is to make sure the code that is executed prior to jumping to _continue is position independent (which it currently is) and change org 0x7c00 to org 0x7a00. You will also need to change jmp 0x0000:(_continue - 0x200) to jmp 0x0000:_continue

  2. Use org 0x0000 and load segments with appropriate values 0x07c0 and 0x07a0 depending on which segment you need to access. By having and origin point of 0x0000 the code and data generated is relative to the beginning of a segment (which you can change), not the beginning of memory.

  3. You can use NASM's segment directive to change the origin point of the code using the vstart (Virtual Memory Address) option. You can use a segment directive with the start (Load Memory Address) option to change the file offset where the boot signature is placed.

Other issues in your code:

  • As @RossRidge pointed out if an error occurs (Carry Flag set) after a disk operation it will get into an infinite loop because you use CX register which is also used in doing Int 13h/AH=02h. You also use CX for the disk reset retry counter and the disk operation.
  • In general you can avoid checking for any error on Int 13h/AH=0 disk reset and remove the retry loop for that operation. You should only have to reset the disk if a previous disk operation failed. Retrying a disk operation three times was normal on real hardware.
  • When your code successfully reads the new code and data to 0x7c00 it displays an error message. It should probably print a message that the disk read was successful.

Code using option 1:

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org 0x7a00
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    xor     ax, ax
    mov     ds, ax
    mov     es, ax
    mov     ss, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     si, 0x7c00
    mov     di, 0x7a00
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x0000:(_continue)

_continue:

; Reset boot disk (try it 3 times before error message is printed)
    mov     si, 4

_reset:
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
_load:
    dec     si
    je      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    mov     bx, 0x7c00
    int     0x13
    jc      _load

    mov     si, loaded_msg
    call    print

; Jump to the second boot sector
    jmp     0x0000:0x7c00

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

loaded_msg:             db              "Operating system loaded", 0xa, 0xd, 0x0
error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Fill the rest of the 512 bytes with 0, byte 510 and 511
; contains 0xaa55 (boot signature for BIOS)

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

Code using option 2:

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org 0x00
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    mov     ax, 0x7c0
    mov     ds, ax
    mov     ss, ax

    xor     ax, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     ax, 0x7a0
    mov     es, ax
    xor     si, si
    xor     di, di
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x07a0:(_continue)

_continue:

    mov     ax, 0x7c0
    mov     es, ax
    mov     ax, 0x7a0
    mov     ds, ax

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
    mov     si, 4

; Reset boot disk
_reset:
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13

_load:
    dec     si
    je      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    xor     bx, bx
    int     0x13
    jc      _load

    mov     si, loaded_msg
    call    print

; Jump to the second boot sector
    jmp     0x0000:0x7c00

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

loaded_msg:             db              "Operating system loaded", 0xa, 0xd, 0x0
error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Fill the rest of the 512 bytes with 0, byte 510 and 511
; contains 0xaa55 (boot signature for BIOS)

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

Code using option 3:

BOOT_ORG EQU 0x7c00

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org BOOT_ORG
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    xor     ax, ax
    mov     ds, ax
    mov     es, ax
    mov     ss, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     si, 0x7c00
    mov     di, 0x7a00
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x0000:_continue

; The code and data past this point will have an origin point (vstart)
; relative to 0x7a00. Align=1 for no padding.

section bootreloc vstart=(($-$$)+0x7a00) align=1
_continue:

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
    mov     si, 4

; Reset boot disk
_reset:
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13

_load:
    dec     si
    jz      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    mov     bx, 0x7c00
    int     0x13
    jc      _load

    mov     si, loaded_msg
    call    print

; Jump to the second boot sector

    jmp     0x0000:0x7c00

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

loaded_msg:             db              "Operating system loaded", 0xa, 0xd, 0x0
error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Set position to 510 bytes from BOOT_ORG so that bytes 510 and 511
; in te disk image will contain 0xaa55 (boot signature for BIOS)

section bootsig start=(BOOT_ORG+510)
dw 0xaa55

Upvotes: 4

Related Questions