Wednesday, September 14, 2011

Bootloader


The below assembly code loads the secondary bootloader (boot2.bin) at address 0x8000 from the FAT12 filesystem and jumps to it.


;_______________________________________________
;    File name : boot.asm |
;    Authour : M.Alexander |
;    Mail : programmer_83@hotmail.com |
;    Date : 09-05-2004 |
;    Description : Primary Bootloader |
;_______________________________________________|


[BITS 16]


; Memory Map
;_______________________________________________
; |
;      _____________________ |
;     |    |  <-- 0x0000 |
;     |    | |
;     |        STACK    | |
;     |    | |
;     |_____________________|  <-- 0x05FF |
;     |    |  <-- 0x0600 |
;     |       FAT COPY    | |
;     |_____________________|  <-- 0x1800 |
;     |////////UNUSED///////| |
;     |_____________________|  <-- 0x2000 |
;     |    | |
;     |    ROOT DIRECTORY   | |
;     |_____________________|  <-- 0x3C00 |
;     |/////////////////////| |
;     |////////UNUSED///////| |
;     |/////////////////////| |
;     |_____________________|  <-- 0x7C00 |
;     |    | |
;     | PRIMARY BOOTLOADER  | |
;     |_____________________|  <-- 0x7E00 |
;     |/////////////////////| |
;     |///////UNUSED////////| |
;     |/////////////////////| |
;     |_____________________|  <-- 0x8000 |
;     |    | |
;     |SECONDARY BOOTLOADER | |
;     |_____________________|  <-- ?? |
; |
;_______________________________________________/


%define FAT_CPY 0x0600
%define DIR_CPY 0x2000
%define SEC_BL 0x8000


[org 0x7C00]


jmp short start
nop


OEM_IDENT db 'FAT12FLP'
BYTES_PER_SCT dw 0200h
SCTS_PER_CLST db 01h
RESERVED_SCTS dw 01h
NO_OF_FATS db 02h
ROOT_ENT dw 0E0h
NO_OF_SCTS dw 0B40h
MEDIA_DCPTR db 0F0h
SCTS_PER_FAT dw 09h
SCTS_PER_TRK dw 012h
HDS_PER_CYL dw 02h
HDN_SCTS dd 0h


start:


mov ax, 0
mov ds, ax
mov es, ax
mov ss, ax       ; Initialize segment registers
mov ax, 0x5ff
mov sp, ax       ; Setup Stack space


sti       ; Enable Interrupts


;____________________________________________________________.
;     Loads FAT copy into main memory at address 0x0600      |
;____________________________________________________________|


xor ax, ax
add word ax, [RESERVED_SCTS]
call trans_add
mov ah, 0x02
mov al, [SCTS_PER_FAT]
mov dl, 0x00
mov bx, FAT_CPY
int 13h


;____________________________________________________________.
;     Loads Directory Entries into main memory at     |
;     address 0x0600     |
;____________________________________________________________|


mov al, [SCTS_PER_FAT]
mul byte [NO_OF_FATS]
add word ax, [RESERVED_SCTS]
call trans_add
mov ah, 0x02
mov al, 0x0E
mov dl, 0x00
mov bx, DIR_CPY
int 13h


;____________________________________________________________.
;  Calculates the start of data area and saves it in the     |
;  variable DATA_AREA for future use.     |
;____________________________________________________________|


mov ax, [SCTS_PER_FAT]
mov bx, [NO_OF_FATS]
mul bx
add ax, [RESERVED_SCTS]
mov bx, ax
mov ax, [ROOT_ENT]
shl ax, 0x05
shr ax, 0x09
add ax, bx
mov [DATA_AREA], ax


;____________________________________________________________.
;     Searching for the secondary file begins here.     |
;____________________________________________________________|


mov bx, [ROOT_ENT] ; Move the number of root entries into bx (counter)
mov dx, DIR_CPY ; Move the address of Directory entry into dx
srch:
cld ; Clear the direction flag
mov di, sec_file ; Move the address of the secondary file into di
mov si, dx ; Load the source address
mov cx, 0x0b ; Number of characters to compare (8+3)
repe cmpsb ; Repeat till the characters not equal. Maximum 0x0b times
jnz short next ; If not found, try next entry




;____________________________________________________________.
;  Loads the secondary file at the address SEC_BL declared   |
;  earlier.     |
;____________________________________________________________|


mov bx, SEC_BL
mov si, dx
add si, 0x1A ; Byte 26 & 27 of the file entry
mov word ax,[si] ; (Entry cluster value)
push ax ; Push the starting cluster to the stack
load:
xor eax, eax
xor ecx, ecx
xor dx, dx ; Clear out necessary registers


pop ax ; Pop the last computed value for the sector
push ax ; Again save it for future use


cmp ax, 0x0FFF ; If End of sector for the file, jump to exit
jz exit


mov cl, [DATA_AREA]
dec ax
dec ax ; Subtract 2 from the next sector value
add ax, cx ; Converts the data sector into LBA
call trans_add ; Converts LBA into CHS


mov ax, 0x0201
mov dl, 0x00
int 13h ; Read the next data cluster into the main memory


add bx, 0x200 ; Increment the file pointer to load the sector


xor ax, ax
pop ax ; Pop the sector value from the stack
mov cx, 0x03
mul cx ; Multiply the value with 3
rcr ax, 1 ; Divide it by 2 (3/2 = 1.5)
jc carry ; If carry set, decimal number


mov si, ax
add si, 0x0600
mov word ax, [si]
and ax, 0x0fff
push ax
jmp load
carry:
mov si, ax
add si, 0x0600
mov word ax, [si]
shr ax, 4
push ax
jmp load


jmp $ ; File found. write code here
next:
dec bx ; Decrement number of entries to check still
jz exit ; If zero, file not found
add dx, 0x20 ; Point to next entry
jmp short srch ; Compare next entry


exit:
jmp 0000:8000h ; Jump to secondary boot loader code




trans_add:
;____________________________________________________________.
;  FUNCTION :  Translates LBA sector number into CHS value   |
;  INPUT    :  AX = LBA Sector     |
;  OUTPUT   :  CH = Cylinder, DH = Head, CL = Sector     |
;     |
;  FORMULA USED:     |
;  sector   = (LBA % SPT) + 1     |
;  Head   = (LBA / SPT) % HPC     |
;  Cylinder = (LBA / SPT) / HPC     |
;____________________________________________________________|
;     |
div word [SCTS_PER_TRK]   ; LBA / SPT     |
inc dl      ; dl = (LBA % SPT) + 1 |
mov cl, dl      ; cl = sector     |
xor dx, dx      ; Clear out dx reg.    |
div word [HDS_PER_CYL]    ; (LBA / SPT) / HPC    |
mov ch, al      ; ch = cylinder     |
mov dh, dl      ; dh = head     |
ret      ; Return     |
;____________________________________________________________|






print:
;____________________________________________________________.
;  FUNCTION : Prints a string     |
;  INPUT    : SI = String Address     |
;  OUTPUT   : Prints the string     |
;____________________________________________________________|
;     |
push ax ;     |
push bx ;     |
pchar: ;     |
cld ;     |
lodsb ;     |
or al, al ;     |
jz pexit ;     |
mov ah, 0x0e ;     |
mov bx, 0x0007 ;     |
int 10h ;     |
jmp pchar ;     |
pexit: ;     |
pop bx ;     |
pop ax ;     |
ret ;     |
;____________________________________________________________|




sec_file db "BOOT2 BIN"
file_nt_fnd db CR,LF,'File not found',0
file_fnd db CR,LF,'File found',0
DATA_AREA db 0x00
FILE_BUF dw 0x8000


CR equ 0x0d
LF equ 0x0a


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