Table of Content

Loading Program in Boot Sector Code

We can now load and execute a second program in the boot sector code. Below include examples that continue explore this, in particular, how we may load and execute programs with subroutines and how we may dynamically address data or instructions in the second programs.

Experiment and Programming Environment

Refer to the bootstrap tutorial for the experiment and programming environment, and for how to compile and run the programs here.

Example 1 Loading and Executing Programs with Subroutine

The following programs include subroutines that you shall find immediately follows the program below

[org 0x7c00]

START:

mov [BOOT_DRIVE], dl

mov bp, 0x8000
mov sp, bp

mov ah, 0x00                ; resetting disk 
int 0x13 


; pass arguments
mov ah, 0x02                ; int 13h function 02
mov al, 0x02                ; read 2 sectors
push ax

mov ch, 0x00                ; cylinder no.
mov cl, 0x02                ; sector no. (sector 1 is boot sector)
push cx

mov dh, 0x00                ; head no.
mov dl, [BOOT_DRIVE]        ; drive no.
push dx

mov bx, 0x0000              ; read disk data to es:bx
mov es, bx 
push es
mov bx, 0x9000  
push bx

call read_disk              ; read disk data

mov bx, READ_DISK
call print_msg
call print_line

mov cl, [0x9000] 
call print_byte
call print_space

mov cl, [0x9001] 
call print_byte
call print_space

mov cl, [0x9002] 
call print_byte
call print_space

mov cl, [0x9003] 
call print_byte
call print_space

mov bx, 0x0000  ; push es, bx twice; one set for retf, and one set for the main
mov es, bx 
push es
mov bx, 0x9000  
push bx
push es
push bx
retf


%include "read_disk.asm"
%include "print_byte.asm"
%include "print_mem.asm"
%include "print_msg.asm"
%include "print_space.asm"
%include "print_line.asm"


BOOT_DRIVE:
    db 0

READ_DISK:
    db "Read new program from disk sectors.", 0

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

main:
    pop cx
    pop ds

    mov ah, 0x0e
    mov al, 0x0d
    int 0x10

    mov ah, 0x0e
    mov al, 0x0a
    int 0x10

    mov ax, ANNOUNCEMENT
    sub ax, main
    add ax, cx
    mov bx, ax

    call main_print_msg
    jmp $
    
ANNOUNCEMENT:
    db "New program starts...", 0


%include "main_print_msg.asm"

times 1024-($-$$) db 0
times 512 db 0

Required Functions

;
; read_disk.asm
;
; read disk sectors with prototype
;   uint16 read_disk(
;       uint16 offset,
;       uint16 segment,
;       uint8 sector_count, 
;       uint8 cylinder, 
;       uint8 sector, 
;       uint8 head, 
;       uint8 drive)
; the subroutine expects the parameters passed in stack 
;       offset
;       segment
;       cylinder sector
;       head rive
;       0000 0010b count
;       
; return value is also in stack
;       uint16
; the subroutine reads disk via PC BIOS int13h
; See https://en.wikipedia.org/wiki/INT_13H
;
read_disk:
;   for near call
;      ip on the top of the stack
    push ax
    push cx
    push dx
    push bp

;   parameters are at sp+10
    mov bp, sp 
    mov bx, [bp+10]         ; disk data to es:bx
    mov ax, [bp+12]
    mov es, ax

    mov dx, [bp+14]         ; dh dl are head no. and drive no.
    mov cx, [bp+16]         ; ch cl are cylinder and sector no.'s

    mov ax, [bp+18]
    mov ah, 0x02

    push ax
    int 0x13
    pop dx

    jc .DISK_ERROR

    cmp dh, al
    jne .DISK_SHORT_READ

    pop bp
    pop dx
    pop cx
    pop ax

    sub bp, 2*5
    ret


.DISK_ERROR:
    mov bx, DISK_ERROR_MSG
    call print_msg

    jmp $

.DISK_SHORT_READ:
    mov bx, SHORT_READ_MSG
    call print_msg

    jmp $

DISK_ERROR_MSG:
    db "Disk read error!", 0

SHORT_READ_MSG:
    db "Disk read error, short read!", 0
;
; print_byte.asm
;
; print a byte in register cl to hex assuming ASCII encoding
;    void * print_byte(char c) 
print_byte:
    pusha ; Push AX, CX, DX, BX, original SP, BP, SI, and DI.

    mov ch, cl
    shr ch, 4
    and ch, 0x0f

    push cx
    mov cl, ch
    call print_low_4bits
    pop cx

    mov ch, cl
    and ch, 0x0f

    push cx
    mov  cl, ch
    call print_low_4bits
    pop cx

    popa
    ret


; print lower 4 bits in register cl to hex assuming ASCII encoding
;    void * print_byte(char c) 
print_low_4bits:
    pusha
    mov ah, 0x0e

    mov ch, cl
    and ch, 0x0f
    cmp ch, 0x09
    jg A_TO_F

    add ch, '0'
    jmp PRINT_CHAR

A_TO_F:
    sub ch, 0x0a
    add ch, 'A'
    jmp PRINT_CHAR

PRINT_CHAR:
    mov al, ch
    int 0x10

    popa
    ret
;
; print_mem.asm
;

; print memory in hex byte by byte separated by a space
;   void print_mem(void *, short num);
; the parameter is passed via registers ds:bx and cl
print_mem:
    pusha
    mov ah, 0x0e
    
    cmp cl, 0
    je NOTHING_TO_PRINT

    xor ch, ch
LOOP:
    push cx
    mov cl, [ds:bx] 
    call print_byte
    pop cx
    inc bx
    dec cl
    inc ch

    cmp cl, 0
    je NOTHING_TO_PRINT

    and ch, 0x0f
    cmp ch, 0
    jnz DO_PRINT_SPACE 
    call print_line
    jmp LOOP

DO_PRINT_SPACE:
    call print_space
    jmp LOOP

NOTHING_TO_PRINT:
    popa
    ret
;
; print_msg.asm
; 
; we implement a function with interface
;     void print_msg(char* msg)
; where we pass the argument msg via ds:bx
print_msg:
    pusha           ; push all registers to stack
    mov ah, 0x0e
.LOOP:
    mov al, [ds:bx]
    cmp al, 0
    je .DONE_PRINT_MSG
    int 0x10
    inc bx
    jmp .LOOP
.DONE_PRINT_MSG:
    popa            ; pop all registers to stack
    ret
;
; print_space.asm
;
print_space:
    pusha

    mov ah, 0x0e
    mov al, ' '
    int 0x10

    popa
    ret
;
; print_line.asm
;
print_line:
    pusha

    ; line feed    
    mov ah, 0x0e
    mov al, 0x0a
    int 0x10

    ; carriage return
    mov ah, 0x0e
    mov al, 0x0d
    int 0x10

    popa
    ret
;
; main_print_msg.asm
;

; we implement a function with interface
;     void main_print_msg(char* msg)
; where we pass the argument msg via ds:bx
main_print_msg:
    pusha           ; push all registers to stack
    mov ah, 0x0e
.LOOP:
    mov al, [ds:bx]
    cmp al, 0
    je .DONE_PRINT_MSG
    int 0x10
    inc bx
    jmp .LOOP
.DONE_PRINT_MSG:
    popa            ; pop all registers to stack
    ret