Reputation: 543
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...
that I can print something onto the screen by writing chars to b800:0000
that the 2 sectors were read correctly. I dumped the memory at 0x7c00 with bochs and it shows the right values
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
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:
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
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.
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:
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