; This program is an example that shows the assembly language programmer
; how to make a boot loader that starts up the computer from a 1.44MB
; floppy disk without windows, dos or any other operating system and
; executes a .com or .bin file.

; The program is setup to execute a .COM file but can also be changed to
; execute a .BIN file. This program is not setup to execute a .EXE file
; or any other type of file other than .COM and .BIN files.

; This program cannot run a .COM or .BIN file bigger than 65,536 bytes.

; If you try to execute a .COM or .BIN file bigger than 65,536 bytes
; with this program then the. COM or .BIN file will not work properly.

; You are free to modify this program and use it to execute your
; own .COM and .BIN files.

; Microsoft Macro Assembler Version 6.15.8803 was used to compile
; the boot.asm, recovery.asm and the recload.asm file.

; Microsoft Segmented Executable Linker Version 5.31.009 Jul 13 1992
; was used to link the boot.obj, recovery.obj and recload.obj files
; to create the BOOT.COM, RECOVERY.COM and RECLOAD.COM files.

; The command line to compile and link the boot.asm file is:

; ml boot.asm

; after running the command ml boot.asm a file called BOOT.COM
; will be created in the current directory.

; The command line to compile and link the recovery.asm is:

; ml recovery.asm

; after running the command ml recovery.asm a file called RECOVERY.COM
; will be created in the current directory.

; The command line to compile and link the recload.asm is:

; ml recload.asm

; after running the command ml recload.asm a file called RECLOAD.COM
; will be created in the current directory.

; This program creates a boot sector for a 1.44MB floppy disk.
; Because of this you will be able to read the 1.44MB floppy
; disk that is created by this program from dos or windows.

; This program assumes that the RECOVERY.COM file uses the custer
; numbers below in the following order.

; cluster number 2
; cluster number 3
; cluster number 4
; cluster number 5
; cluster number 6
; cluster number 7
; cluster number 8
; cluster number 9
; cluster number 10
; cluster number 11
; cluster number 12
; cluster number 13
; cluster number 14
; cluster number 15
; cluster number 16
; cluster number 17
; cluster number 18
; cluster number 19
; cluster number 20
; cluster number 21
; cluster number 22
; cluster number 23
; cluster number 24
; cluster number 25
; cluster number 26
; cluster number 27
; cluster number 28
; cluster number 29
; cluster number 30
; cluster number 31
; cluster number 32
; cluster number 33
; cluster number 34
; cluster number 35
; cluster number 36
; cluster number 37
; cluster number 38
; cluster number 39
; cluster number 40
; cluster number 41
; cluster number 42
; cluster number 43
; cluster number 44
; cluster number 45
; cluster number 46
; cluster number 47
; cluster number 48
; cluster number 49
; cluster number 50
; cluster number 51
; cluster number 52
; cluster number 53
; cluster number 54
; cluster number 55
; cluster number 56
; cluster number 57
; cluster number 58
; cluster number 59
; cluster number 60
; cluster number 61
; cluster number 62
; cluster number 63
; cluster number 64
; cluster number 65
; cluster number 66
; cluster number 67
; cluster number 68
; cluster number 69
; cluster number 70
; cluster number 71
; cluster number 72
; cluster number 73
; cluster number 74
; cluster number 75
; cluster number 76
; cluster number 77
; cluster number 78
; cluster number 79
; cluster number 80
; cluster number 81
; cluster number 82
; cluster number 83
; cluster number 84
; cluster number 85
; cluster number 86
; cluster number 87
; cluster number 88
; cluster number 89
; cluster number 90
; cluster number 91
; cluster number 92
; cluster number 93
; cluster number 94
; cluster number 95
; cluster number 96
; cluster number 97
; cluster number 98
; cluster number 99
; cluster number 100
; cluster number 101
; cluster number 102
; cluster number 103
; cluster number 104
; cluster number 105
; cluster number 106
; cluster number 107
; cluster number 108
; cluster number 109
; cluster number 110
; cluster number 111
; cluster number 112
; cluster number 113
; cluster number 114
; cluster number 115
; cluster number 116
; cluster number 117
; cluster number 118
; cluster number 119
; cluster number 120
; cluster number 121
; cluster number 122
; cluster number 123
; cluster number 124
; cluster number 125
; cluster number 126
; cluster number 127
; cluster number 128
; cluster number 129

; If the RECOVERY.COM or whatever .COM or .BIN file you want this
; program to run does not use the cluster numbers above or if the
; cluster numbers are not in the same order on the 1.44MB floppy
; disk as above then the RECOVERY.COM or whatever .COM or .BIN
; file you want this program to run will not work properly.

; To make sure that the RECOVERY.COM or whatever .COM or .BIN file
; you want this program to run is using the above cluster numbers
; in the correct order just copy the RECOVERY.COM or whatever .COM
; or .BIN file you want this program to run to the 1.44MB floppy disk
; as the first file on the 1.44MB floppy disk after you have formatted
; the 1.44MB floppy disk.

.model tiny
.code

TIMES   db 1 dup(0EBh)  ; 3 bytes jmp instruction to boot program.
        db 1 dup(3Ch)
        db 1 dup(90h)
        db 8 dup(00h)   ; 8 bytes OEM name and DOS version. ("IBM 4.0").
        dw 1 dup(200h)  ; Bytes per sector.
        db 1 dup(01h)   ; Sectors per cluster. Must be a power of 2
        dw 1 dup(01h)   ; Reserved sectors. Usually 1
        db 1 dup(02h)   ; Fat copies. Usually 2.
        dw 1 dup(0E0h)  ; Maximun root directory entries. Usually 512
        dw 1 dup(0B40h) ; Total sectors. if the partition less than or
                        ; equal to 32m, else 0.
        db 1 dup(0f0h)  ; Media descriptor byte.
        dw 1 dup(09h)   ; Sectors per fat.
        dw 1 dup(12h)   ; Sectors per track.
        dw 1 dup(2h)    ; Number of heads.
        dd 1 dup(00h)   ; Number of hidden sectors.
        dd 1 dup(00h)   ; Total sectors. if the partition is greater than
                        ; 32m, else 0.
        db 1 dup(00h)   ; Physical drive number. 00h = floppy drive or
                        ; 80h = hard drive.
        db 1 dup(00h)   ; Reserved(00h).
        db 1 dup(29h)   ; Extended boot record signature (29h).
        dd 1 dup(00h)   ; Volume serial number.
        db 11 dup(00h)  ; Volume label. NONAME stored if no label.
        db 8 dup(00h)   ; File system ID. FAT12 or FAT16.

; code is located at 07C0:0000. This is segment 07C0h offset 0000
; adjust segment registers

mov     ax, 07C0h
mov     ds, ax 
mov     es, ax 

; create your stack 

mov     ax, 0000h
mov     ss, ax 
mov     sp, 0FFFFh 

readrootfromfloppydiskagain:

mov     si,00000000d

readfloppyagain:

mov   bx,2000h          ; Segment where the information is stored in
mov   es,bx             ; memory that is read from the floppy disk.
mov   bx,0000h          ; Offset where the information is stored in

mov   ah,02h            ; Bios read floppy disk sectors funcation.
mov   al,01h            ; Number of sectors to read from floppy disk.
                        ; You can only read 36 sectors at one time.    
mov   ch,00h            ; Track number to read from floppy disk.
mov   cl,02h            ; Sector number to read from floppy disk.
mov   dh,01h            ; Head number to read from floppy disk.
mov   dl,00h            ; Drive number of floppy drive to read from.
int   13h               ; End of bios read floppy disk sectors
                        ; funcation.

inc     si              ; Read from floppy drive 3 times to make sure the
cmp     si,00000003d    ; read does not fail because of an older bios.
jne     readfloppyagain ; If you have an older bios then the read will
                        ; fail until the floppy drive motor is up to
                        ; speed. We are reading from the floppy drive
                        ; 3 times to make sure the floppy drive motor
                        ; is up to speed.

                                 ; Check to see if FileName RECOVERY.COM
mov   di,bx                      ; exists as the first file in the root
mov   si,offset FileName         ; directory. If RECOVERY.COM does not
mov   cx,11d                     ; exist or is not the first file in the
repz  cmpsb                      ; root directory then the RECOVERY.COM
jne   displaymsginfoerroragain   ; file will not be loaded.

cmp   byte ptr es:[bx + 11d],20h ; Also check that the attribute for the
jne   displaymsginfoerroragain   ; RECOVERY.COM is 20h. 20h = archive
                                 ; attribute only. If the archive attribute
                                 ; has changed then we assume that the file
jmp   noerror                    ; RECOVERY.COM is not on the disk.

displaymsginfoerroragain:

mov     si, offset msginfoerror 

; Display ASCIIZ string at ds:si using the BIOS.

getnextcharactertodisplayforerror:

lodsb                          ; load next character                                       
cmp     al,'$'                 ; Test for last character
je      lastcharacterdisplayedforerror
mov     ah, 0Eh                ; BIOS funcation teletype 
mov     bh, 00h                ; display page is 0 
mov     bl, 07h                ; text attribute 
int     10h                    ; invoke BIOS 
jmp     getnextcharactertodisplayforerror

lastcharacterdisplayedforerror: 

chkforenterkey:

mov   ah,00h
int   16h
cmp   al,0dh
je    readrootfromfloppydiskagain
jmp   chkforenterkey

noerror:

mov     si, offset msginfobooting 

; Display ASCIIZ string at ds:si using the BIOS.

getnextcharactertodisplayforbooting:

lodsb                          ; load next character
cmp     al,'$'                 ; Test for last character.
je      lastcharacterdisplayedforbooting
mov     ah, 0Eh                ; BIOS funcation teletype 
mov     bh, 00h                ; display page is 0 
mov     bl, 07h                ; text attribute 
int     10h                    ; invoke BIOS 
jmp     getnextcharactertodisplayforbooting

lastcharacterdisplayedforbooting: 

mov     bx,2000h     ; Segment where the information is stored in
mov     es,bx        ; memory that is read from the floppy disk.
mov     bx,0000h     ; Offset where the information is stored in
                     ; memory that is read from the floppy disk.

mov     di,00000128d ; di contains how many sectors you want to read.
                     ; Don't set di to more than 128 because this
                     ; program can't read a file bigger then 64KB
                     ; 64KB is 65536 bytes.

mov     si,00000003d ; si contains how many times you want to read
                     ; each sector.   

                     ; You can only read 1 sector at one time without
                     ; problems.

                     ; We are reading from each sector of the floppy
                     ; disk in the floppy drive 3 times to make sure
                     ; the read does not fail because of an older bios.
                     ; If you have an older bios then the read will
                     ; fail until the floppy drive motor is up to
                     ; speed. We are reading from each sector of
                     ; the floppy disk in the floppy drive 3 times to
                     ; make sure the floppy drive motor is up to speed.
                     ; We really only need to read 1 sector 3 times from
                     ; the floppy disk to make sure that the floppy drive
                     ; motor is up to speed. The reason we are reading
                     ; each sector 3 times is because we are not
                     ; checking the carry flag to see if an error
                     ; occurred. The reason we are not checking the carry
                     ; flag is because some bios will set the carry flag
                     ; when reading from the floppy disk sectors even
                     ; when no error has occurred.

                     ; Below is the Track, Sector and head number
                     ; that we are starting our read from.

mov   ch,00h         ; Track number to read from floppy disk.
mov   cl,16d         ; Sector number to read from floppy disk.
mov   dh,01h         ; Head number to read from floppy disk.

readfloppyagain1:
   
mov   ah,02h         ; Bios read floppy disk sectors funcation.
mov   al,01h         ; Number of sectors to read from floppy disk.
mov   dl,00h         ; Drive number of floppy drive to read from.
int   13h            ; End of bios read floppy disk sectors
                     ; funcation.
dec     si
cmp     si,00000000d          ; Check si to make sure each sector has been
jne     readfloppyagain1      ; read 3 times.      

; Display dot at ds:si using the BIOS.

push    si
push    bx
cmp     counter,00h
jne     nospace

mov     ah,0Eh                ; BIOS funcation teletype
mov     al,20h                ; We are first moving the cursor
                              ; 3 spaces to the right.          
mov     bh,00h                ; display page is 0
mov     bl,07h                ; text attribute 
int     10h                   ; invoke BIOS 
int     10h                   ; invoke BIOS 
int     10h                   ; invoke BIOS 

nospace:

mov     ah,0Eh                ; BIOS funcation teletype
mov     al,2Eh                ; Display . character
mov     bh,00h                ; display page is 0
mov     bl,07h                ; text attribute 
int     10h                   ; invoke BIOS 

pop     bx
pop     si
add     counter,01h           ; add 1 to counter.
cmp     counter,64d           ; check if counter is 64.
je      nextline              ; drop to next line if
                              ; counter is 64.

jmp     continue              ; If counter is not 64
                              ; then don't drop to
                              ; nextline
nextline:

push    si
push    bx

mov     ah,0Eh                ; BIOS funcation teletype
mov     bh,00h                ; display page is 0 
mov     al,0Dh                ; Carriage return character
mov     bl,07h                ; text attribute
int     10h                   ; Invoke BIOS
                              
mov     ah,0Eh                ; BIOS funcation teletype
mov     bh,00h                ; display page is 0 
mov     al,0Ah                ; Line Feed character
mov     bl,07h                ; text attribute
int     10h                   ; invoke BIOS 

pop     bx
pop     si

mov     counter,00h

continue:

mov     si,00000003d          ; Set si to read next sector 3 times.
cmp     cl,18d                ; Check if sectors has reached 18. If
je      setcylandhdandsector  ; sectors are 18 then setup sectors,
inc     cl                    ; Heads and Tracks to read from next
                              ; sector.

dec     di                    ; Set di to read from next sector.
add     bx,512d               ; Setup offset where data from
                              ; next sector will be read into
                              ; memory.

cmp     di,00000000d          ; Check if di is 00000000d. If di is
jne     readfloppyagain1      ; 00000000d then we have read all the
                              ; sectors.
jmp     done

setcylandhdandsector:
                              
dec     di                    ; Set di to read from next sector.
add     bx,512d               ; Setup offset where data from
                              ; next sector will be read into
                              ; memory.

mov     cl,01h                ; Set sector number to 1.
                              ; Sector number is always set to 1.

cmp     dh,01h                ; Check if head is 1. If head is one then
je      setcylandhd           ; set it to 0.

mov     dh,01h                ; Head is 0 so we set head to 1
jmp     readfloppyagain1      ; Perform next read

setcylandhd:

inc     ch                    ; Set next Track to read from

mov     dh,00h                ; Set head to 0
jmp     readfloppyagain1      ; Perform next read.

done:

 db 0EAh                      ; Jmp instruction that jumps to 2000:0000
 dw 0000h                     ; Offset in memory where data is stored.
 dw 2000h                     ; Segment in memory where data is stored.

; Below are 3 more lines that you could use to jmp to the memory address
; and execute the program.
; You could use the 3 lines below instead of the 3 lines above to
; jmp to the memory address 2000:0000 and execute the program.

; The 3 instructions below can only be used with a 386 processor or
; higher.

; push    WORD ptr 2000h    ; Segment in memory where data is stored.
; push    WORD ptr 0000h    ; Offset in memory where data is stored.
; retf                      ; Jmp to address 2000:0000 and execute
                            ; program.

; Below is the filename that you want to run when the computer boots up
; from the floppy disk. The program RECOVERY.COM is the default program
; but you could change the name below to load any .com or .bin file you
; want. After making changes you will have to recompile the program.

FileName       db "RECOVERYCOM" 

msginfoerror   db 0Dh,0Ah
               db "   File not found. Please insert floppy disk",0Dh,0Ah
               db "   with RECOVERY.COM file and press the enter",0Dh,0Ah
               db "   key.",0Dh,0Ah
               db 0Dh,0Ah,07h,"$"

counter        db 1 dup (00h)

msginfobooting db 0Dh,0Ah,0Dh,0Ah
               db "   Loading the RECOVERY.COM file into memory.",0Dh,0Ah,"$"

; The number 1 in the line of code below needs to be changed
; everytime you add or remove code from this file. The line
; below makes sure that 55h AAh are the last 2 bytes of the
; boot sector. You will need to uncomment the line before
; you change it.

;               db 1 dup(00h) ; Boot program code.

               dw 1 dup(0AA55h)

end
