Home > Software design >  Second sector cannot be loaded in boot file
Second sector cannot be loaded in boot file

Time:06-06

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 the bits 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 the bits 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
  • Related