This is a part of the code of a small sample of bootloader.
It displays "myos" ONLY, but does not display "ok".
. . .
mov si, statement1
call print_string
; load second sector into memory
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
mov dl, 0x80 ; sector read from fixed/usb disk
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, _OS_Stage_2 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
jmp _OS_Stage_2 ; jump to second stage
. . .
statement1 db "myos", 0
; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00 ;set 512 bytes for boot sector which are necessary
dw 0xAA55 ; boot signature 0xAA & 0x55
_OS_Stage_2:
. . .
mov si, statement2
call print_string
statement2 db "ok", 0
; add how much memory we need
times (1024 - ($-$$)) db 0x00
Here is the code to jump to _OS_Stage_2. It does not work.
THE FULL SOURCE CODE IS INCLUDED HERE
bits 16] ; tell assembler that working in real mode(16 bit mode)
[org 0x7c00] ; organize from 0x7C00 memory location where BIOS will load us
start: ; start label from where our code starts
xor ax,ax ; set ax register to 0
mov ds,ax ; set data segment(ds) to 0
mov es,ax ; set extra segment(es) to 0
mov bx,0x8000
mov ax,0x13 ;clears the screen
int 0x10 ;call bios video interrupt
mov ah,02 ;clear the screen with big font
int 0x10 ;interrupt displayt
; cursor position
mov al, 2
mov ah, 0
mov bl, 4
mov bh, 0
int 0x10
mov si, command_prompt
call print_string
mov ax,0x00 ; get keyboard input
int 0x16 ; interrupt for hold & read input
; load second sector into memory
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
mov dl, 0x80 ; sector read from fixed/usb disk
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, _OS_Stage_2 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
jmp _OS_Stage_2 ; jump to second stage
int 0x19
print_string:
mov ah, 0x0E ; value to tell interrupt handler that take value from al & print it
.repeat_next_char:
lodsb ; get character from string
cmp al, 0 ; cmp al with end of string
je .done_print ; if char is zero, end of string
int 0x10 ; otherwise, print it
jmp .repeat_next_char ; jmp to .repeat_next_char if not 0
.done_print:
ret ;return
command_prompt db "myos", 0
; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00 ;set 512 bytes for boot sector which are necessary
dw 0xAA55 ; boot signature 0xAA & 0x55
_OS_Stage_2:
mov al,2 ; set font to normal mode
mov ah,0 ; clear the screen
int 0x10 ; call video interrupt
mov si, statement
call print_string
statement db "ok", 0
; add how much memory we need
times (1024 - ($-$$)) db 0x00
The above code is assembled by NASM as below by ./build-linux.sh (file) in ubuntu with qemu emulator.
#!/bin/sh
if test "`whoami`" != "root"
then
echo "You must be logged in as root to build (for loopback mounting)"
echo "Enter 'su' or 'sudo bash' to switch to root"
exit
fi
if [ ! -e disk_images/os.flp ] then
echo ">>> Creating new OS floppy image..."
mkdosfs -C disk_images/os.flp 1440 || exit
fi
echo ">>> Assembling bootloader..."
nasm -O0 -w orphan-labels -f bin -o source/bootload/nasma/boot.bin source/bootload/nasma/boot.asm || exit
echo ">>> Adding bootloader to floppy image..."
dd status=noxfer conv=notrunc if=source/bootload/nasma/boot.bin of=disk_images/os.flp || exit
echo ">>> Creating CD-ROM ISO image..."
rm -f disk_images/os.iso
mkisofs -quiet -V 'OS' -input-charset iso8859-1 -o disk_images/os.iso -b os.flp disk_images/ || exit
echo '>>> Done!'
The test-linux (file) runs the program as below
#!/bin/sh
qemu-system-i386 -soundhw pcspk -drive format=raw,file=disk_images/os.flp,index=0,if=floppy
CodePudding user response:
Main problem: You're hardcoding unit 80h for loading from your boot load unit, but you're passing the image as a diskette drive to qemu so you should use unit 00h.
Solution: Preserve the dl
register (part of dx
) as it was upon entry to your loader. The prior loader passes the current boot load unit to you in this register so just use that.
Additional nitpicks:
No error handling, it just crashes when failing.
Stack should be set up by your code to avoid possibly interfering with your sector load.
After you finished running you should make some sort of infinite loop to end, rather than letting execution continue past the end of your code. I made a loop around
sti
\hlt
to save power.The full source you listed has another mistake, it is missing the opening square bracket
[
for thebits
directive. (This appears to be allowed by NASM but it is wrong.) Dropping the closing square bracket is also valid, there are two forms of thebits
directive either with or without the brackets.You aren't mounting anything in your build script so you don't need to be root.
You don't need to create an ISO image at this point and did not use it to run your program in fact.
You don't need to create a DOS filesystem if you're just overwriting the first two sectors anyway, which makes the filesystem unusable. I replaced this with another
dd
command.
Here's my fixed script and source, except for the error handling and stack setup which is still missing. Script:
#!/bin/sh
if [ ! -e disk_images/os.flp ]
then
echo ">>> Creating new OS floppy image..."
dd if=/dev/zero of=disk_images/os.flp bs=1024 count=1440 || exit
fi
echo ">>> Assembling bootloader..."
nasm -O0 -w orphan-labels -f bin -o source/bootload/nasma/boot.bin source/bootload/nasma/boot.asm || exit
echo ">>> Adding bootloader to floppy image..."
dd status=noxfer conv=notrunc if=source/bootload/nasma/boot.bin of=disk_images/os.flp || exit
echo '>>> Done!'
Source: (Note the push dx
, pop dx
, and sti
\ hlt
loop.)
[ bits 16] ; tell assembler that working in real mode(16 bit mode)
[org 0x7c00] ; organize from 0x7C00 memory location where BIOS will load us
start: ; start label from where our code starts
xor ax,ax ; set ax register to 0
mov ds,ax ; set data segment(ds) to 0
mov es,ax ; set extra segment(es) to 0
mov bx,0x8000
push dx
mov ax,0x13 ;clears the screen
int 0x10 ;call bios video interrupt
mov ah,02 ;clear the screen with big font
int 0x10 ;interrupt displayt
; cursor position
mov al, 2
mov ah, 0
mov bl, 4
mov bh, 0
int 0x10
mov si, command_prompt
call print_string
mov ax,0x00 ; get keyboard input
int 0x16 ; interrupt for hold & read input
; load second sector into memory
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
pop dx
; mov dl, 0x80 ; sector read from fixed/usb disk
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, _OS_Stage_2 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
jmp _OS_Stage_2 ; jump to second stage
int 0x19
print_string:
mov ah, 0x0E ; value to tell interrupt handler that take value from al & print it
.repeat_next_char:
lodsb ; get character from string
cmp al, 0 ; cmp al with end of string
je .done_print ; if char is zero, end of string
int 0x10 ; otherwise, print it
jmp .repeat_next_char ; jmp to .repeat_next_char if not 0
.done_print:
ret ;return
command_prompt db "myos", 0
; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00 ;set 512 bytes for boot sector which are necessary
dw 0xAA55 ; boot signature 0xAA & 0x55
_OS_Stage_2:
mov al,2 ; set font to normal mode
mov ah,0 ; clear the screen
int 0x10 ; call video interrupt
mov si, statement
call print_string
haltloop:
sti
hlt
jmp haltloop
statement db "ok", 0
; add how much memory we need
times (1024 - ($-$$)) db 0x00