Implementing bootloader
[html]I have been away from my project for about 3 months and started resuming on the bootloader.
Basically I have 3 file:
copyraw.exe - copies boot.bin to mbr (without overwriting p-table) and copies exp.exe below to sector 1 and so on.
boot.bin - bootloader that is less than 512 bytes.
exp.exe - actual executable that is loaded by bootloader.
Initially no concern regarding the FAT, it is all raw stuff.
To prove the bootloader is loaded successfully to 0000:7c00h, i put small snippet to printed chars starting from 0 incrementing by 2 10 times (02468... ) to beginning of video buffer area 0000:b800h This part works.
After that boot loader should copy exp.exe file starting from sector 1 to 0000:8000h and subsequent sectors to 0000:8200h and so on.
The exp.exe starts with printing ABCD... 10h times to video buffer area 0000:b820h. This is where it does not seem to work anymore which I am still checking.
Here I put down source for bootloader (boot.asm), exp.exe (loadable executable) and copyraw (the one that raw copies bootloader and executable into disk and its output log below.
;boot.asm
686p
include macros.inc
; re-defined the part of disk.inc here so that no need to include
; disk.asm,
DAP_OFFSET_SIZE = 0
DAP_OFFSET_UNUSED = 1
DAP_OFFSET_NO_SECTORS = 2
DAP_OFFSET_BUFFER_PTR = 4
DAP_OFFSET_SECTOR_START = 8
sta segment para stack use16 'stack'
sta ends
data segment para public 'data'
data ends
code segment para public use16 'code'
assume cs:code, ds:data,ss:sta
M_EXTERNDEF
; code to be copied to 1st sector of HDD.
; this code will do a boot strap by copying main program into another
; program and will do a jmp.
; the size of this function must be less than 512 bytes in order to
; fit onto 1st sector.
main proc far
; Print a series of char into screen buffer, to verify this code has been reached
; and been executed by a processor.
mov si, 0b800h
mov ds, si
sub si, si ; (DS:SI) = video buffer.
mov cx, 10h ; display 80 times.
mov ax, 0e30h ; char to display byte1: color, byte2: char 0.
loop1:
mov ds:[si], al
inc al ; (AL) = next digit.
cmp al, 39h ; reset to 0 if 9
jb @f
mov al, 30h
@@:
add si, 2 ; (SI) = next char.
loop loop1
mov dl, 80h ; disk 0
mov si, 7e00h ;
mov ds, si
sub si, si ; (DS:SI) = 0000:7e00h = DAP area.
mov byte ptr ds:[si+DAP_OFFSET_SIZE], 10h
mov byte ptr ds:[si+DAP_OFFSET_UNUSED], 00h
mov word ptr ds:[si+DAP_OFFSET_NO_SECTORS], (400h * 64) ; copy 64k
mov word ptr ds:[si+DAP_OFFSET_BUFFER_PTR], 8000h
mov word ptr ds:[si+DAP_OFFSET_BUFFER_PTR+2], 00h
mov dword ptr ds:[si+DAP_OFFSET_SECTOR_START], eax
mov dword ptr ds:[si+DAP_OFFSET_SECTOR_START+4], 0h ; set starting sector No for upper 48 lba.
mov ah, 42h ; (AH) = fcn No. for extended disk read.
int 13h
sub si, si
mov ds, si
mov si, 8000h ; (DS:SI) = location, 0:8000h to jump to, pt of no ret.
jmp word ptr ds:[si]
; Should never reach here. Also up to this point should better not exceed 512 bytes.
fileEnd db 55h, 0aah
main endp
code ends
end main
;exp.asm
.686p
include macros.inc
include exp.inc
code segment para public use16 'code'
assume cs:code, ds:data,ss:sta
M_EXTERNDEF
main proc far
mov ax, DATA
mov ds, ax
mov si, 0b800h
add si, 20h ; Leave bootloader written area behind.
mov ds, si
sub si, si ; (DS:SI) = video buffer.
mov cx, 10h ; display 80 times.
mov ax, 'A' ; char to display byte1: color, byte2: char 0.
loop1:
mov ds:[si], al
inc al ; (AL) = next digit.
cmp al, 'E' ; reset to 0 if 9
jb @f
mov al, 'A'
@@:
add si, 2 ; (SI) = next char.
loop loop1
; rawcopy.asm:
;
include macros.inc
include disk.inc
; re-defined the part of disk.inc here so that no need to include
; disk.asm,
DAP_OFFSET_SIZE = 0
DAP_OFFSET_UNUSED = 1
DAP_OFFSET_NO_SECTORS = 2
DAP_OFFSET_BUFFER_PTR = 4
DAP_OFFSET_SECTOR_START = 8
sta segment para stack use16 'stack'
sta ends
; here we define variables bootloader.
data segment para public 'data'
fileName db "boot.bin", 0
dosHdrBuffer db 512 dup (36h)
mbrBuffer db 512 dup (37h) ; mbr write buffer.
mbrReadBuffer db 512 dup (35h) ; mbr read first and partition table is copied to mbrBuffer
filePointer dw ?
readSize dw ?
; here we define variables for file being loaded. will be kernel.
fileName1 db "exp.exe$"
mbrBuffer1 db 512 dup (38h)
filePointer1 dw ?
readSize1 dw ?
counter dd 0
; disk access packet area.
dap db 16 dup(31h)
data ends
code segment para public use16 'code'
assume cs:code, ds:data,ss:sta
M_EXTERNDEF
; code to be copy mbr code to 1st sector of HDD (sector No. 0).
; this will open boot.bin (bootloader) file and reads first 1024
; (should read entire file) bytes into pre-defined buffer and will copy
; the entire file content (minus DOS header) into Disk 80h sector 0.
main proc far
; do not run from windows, prevent accidental erase of MBR in case it is allowed.
mov eax, cr0
test eax, 01
jz mainLab1
M_PRINTF "\nCan not run from protected mode."
jmp mainExit
mainLab1:
; Read sector 0 first. Doing so will help preserve the partition table
; when we write back after loading boot.bin and overwrite first 200h-64 bytes.
mov dl, 80h ; disk 0
mov si, DATA
mov ds, si
lea si, dap ; (DS:SI) = SEG:OFF pointer to dap.
; Prepare DAP area.
mov cx, 1 ; (CX) = No. of sectors.
mov di, DATA
mov es, di
lea di, mbrBuffer ; (DS:SI) = SEG:OFF pointer to dap.
mov byte ptr ds:[si+DAP_OFFSET_SIZE], 10h
mov byte ptr ds:[si+DAP_OFFSET_UNUSED], 00h
mov word ptr ds:[si+DAP_OFFSET_NO_SECTORS], cx
mov word ptr ds:[si+DAP_OFFSET_BUFFER_PTR], di
mov word ptr ds:[si+DAP_OFFSET_BUFFER_PTR+2], es
mov dword ptr ds:[si+DAP_OFFSET_SECTOR_START], 0h
mov dword ptr ds:[si+DAP_OFFSET_SECTOR_START+4], 0h ; set starting sector No for upper 48 lba.
; Issue read DOS function to read into region defined by DAP area.
mov ah, 42h ; (AH) = fcn No. for extended disk read.
int 13h ; (AH) = return code if error reading.
jnc mainLab1a
M_PRINTF "\nRead sector 0 failure. Exiting (Error code): "
M_PRINTBYTE ah
jmp mainExit
mainLab1a:
M_PRINTF "\nRead sector 0 success."
M_PRINTSTR_1616_NL es, di, 0, 020h
; Open bootstrap file. Will copy first 512-64 bytes overwriting the DAP area.
mov ah, 3dh ; (AH) = file open int 21h code.
sub al, al ; (AL) = RO mode.
mov dx, DATA
mov ds, dx
lea dx, fileName ; (DS:DX) = pointer to filename string.
M_PRINTF "\nbootloader file (boot.bin): "
M_PRINTSTR_1616_NL ds, dx, 1, 7
int 21h ; (AX) = file handle.
jnc mainLab2
M_PRINTF "\nFailure opening boot.bin file (error code): "
M_PRINTWORD ax
jmp mainExit
; Read till the end or up to 1024 - 64 (dos header + mbr - partition table size)
; into buffer if FF pointer is successful.
mainLab2:
M_PRINTF "\nSuccess opening file boot.bin (fileHandle), reading: "
M_PRINTWORD ax
mov filePointer, ax ; save file pointer.
mov ah, 3fh ; (AH) = file read int 21h code.
mov bx, filePointer ; (BX) = file pointer.
mov cx, 400h - 64 ; (CX) = 1024 - bytes but leave partition table area.
mov dx, DATA
mov ds, dx
lea dx, dosHdrBuffer ; (DS:DX) = 16:16 buffer to read into.
int 21h ; (AX) = No. of bytes read if success.
jnc mainLab3
M_PRINTF "\nFailed to read boot.bin file (Error code): "
M_PRINTWORD ax
jmp mainExit
; copy to disk 80h sector 0. Since the first 200h bytes of read is dosheader
; we point the DS:SI to right after dosHeaderBuffer which is mbrBuffer
; which itself is 512 bytes.
mainLab3:
M_PRINTF "\nRead success for boot.bin (No. of bytes): "
M_PRINTWORD ax
mov readSize, ax ; save read size.
mov dl, 80h ; disk 0
; Start writing DAP area back to sector 0.
mov si, DATA
mov ds, si
lea si, dap ; (DS:SI) = SEG:OFF pointer to dap.
mov di, DATA
mov es, di
lea di, mbrBuffer ; (DS:SI) = SEG:OFF pointer to dap.