Category >
ASSEMBLYLANGUAGE
|| Published on :
Saturday, October 10, 2020 || Views:
831
||
write a bootloader in assembly
Here Pawan Kumar will explain how to boot-sector programming
; sector.asm
;
; writes a boot sector out to the floppy disk in the A: drive
;
; The input file is assumed to be a binary file with the relevant code
; at offset 7C00h relative to the beginning of the file. This is because
; when the sector loader transfers control to the boot sector, it's at
; address 0:7C00h. Rather than clutter up the boot loader source with
; a bunch of ugly offsets, we simply use an ORG 7C00h instead and let
; the linker insert a bunch of empty space which this program skips over.
;
; Style Note:
; There aren't any hardwired numbers in this code. That is to say,
; equates and macros are used to render gibberish like this:
; mov ax,4c00h
; int 33
;
; into somewhat self-documenting code like this:
; DosInt DOS_TERMINATE, 0
;
; This is done to make the code more readable, and comprehensible, and
; to aid in maintenance by not littering mysterious constants throughout
; the code. Please be kind to animals (specifically your fellow
; programmers) and use this practice in your own code.
;
;
STACKSIZE = 200h ; this is how much stack we'll allocate
SECTORSIZE = 200h ; size of the boot sector on a floppy
CMD_LINE_LEN = 80h ; offset of the command line length (one byte)
; relative to the beginning of the PSP.
CMD_LINE = 81h ; the offset relative to the beginning of the
; PSP that is the start of the command line
; arguments.
DOS_OPEN_HANDLE = 03dh ; open file
READ_ONLY_DENY_NONE = 020h ; file open mode
DOS_MOVE_HANDLE = 042h ; move file pointer
WHENCE_BEGIN = 0 ; move pointer relative to beginning
WHENCE_CURRENT = 1 ; move pointer relative to current location
WHENCE_EOF = 2 ; move pointer relative to end of file
DOS_READ_HANDLE = 03fh ; read from an open file handle
DOS_CLOSE_HANDLE = 03eh ; close an open file handle
DOS_WRITE_HANDLE = 040h ; write to open file
DOS_TERMINATE = 04ch ; terminate and exit
DOS_INT = 021h
; various named character constants
NUL = 0
CR = 13
LF = 10
SPACE = ' '
GenericInt macro function, subfunction
ifb <subfunction>
mov ah,function
else
mov ax,(function SHL 8) OR (subfunction AND 0ffh)
endif
endm
DosInt macro function, subfunction
GenericInt <function>,<subfunction>
int DOS_INT
endm
BDISK_WRITE_SECTOR = 03h
BDISK_INT = 013h
; constants unique to this program
FILE_OFFS_LO = 7C00h ;
FILE_OFFS_HI = 0000h ;
BOOT_DRIVE = 0 ; we'll be writing to drive A:
BOOT_HEAD = 0 ; head 0 is the boot head
BOOT_CYLSECT = 0001h ; a word value with the following format
; bits 15-8 low bits of cylinder
; bits 7-6 high two bits of cylinder
; bits 5-0 sector
NUM_SECTORS = 1 ; number of sector to write to disk
model small
.386
.stack STACKSIZE
.code
;**********************************************************************
; program code start
;**********************************************************************
Start:
; parse the command line args
mov cl,byte ptr [DGROUP:CMD_LINE_LEN] ; read the length byte
; NOTE that the command line length isn't really part of the
; DGROUP group, but DS currently points to the PSP, and if we
; omit the DGROUP override, the assembler thinks we're trying
; to load a constant instead of the contents of the memory loc.
; In other words, it's ugly but it has a purpose.
or cl,cl ; check for zero
jz Usage ; no command line args
mov si,CMD_LINE ;
mov al,' ' ;
repe cmpsb ; burn off leading spaces
mov dx,si ; save that starting point
repne cmpsb ; scan for next space (if any)
cmp byte ptr [si],SPACE ; if it's > space char,
ja skip ; skip the nul termination
mov byte ptr [si],NUL ; terminate with a NUL char
skip:
; first, open the file
DosInt DOS_OPEN_HANDLE, READ_ONLY_DENY_NONE
mov si,seg DGROUP ;
mov ds,si ;
mov es,si ; point 'em all over there
mov si,offset err_fopen ; can't open input file
jc ErrorExit
; the file's open, so move the file pointer to offset 7C00h
mov bx,ax ; fetch the file handle
mov cx,FILE_OFFS_HI
mov dx,FILE_OFFS_LO
DosInt DOS_MOVE_HANDLE, WHENCE_BEGIN
mov si,offset err_fmove ;
jc ErrorExit ;
; read the data
mov cx,SECTORSIZE ; max number of bytes to read
mov dx,offset buffer ; point ds:dx to buffer
DosInt DOS_READ_HANDLE ;
mov si,offset err_fread ;
jc ErrorExit ;
; close the file
DosInt DOS_CLOSE_HANDLE ; close this file
; now write it out to the floppy disk's boot sector
mov bx,offset buffer ;
mov cx,BOOT_CYLSECT ;
mov dx,(BOOT_HEAD SHL 8) OR (BOOT_DRIVE)
GenericInt BDISK_WRITE_SECTOR, NUM_SECTORS
int BDISK_INT
mov si,offset err_write ;
jc ErrorExit ;
mov si,offset msg_ok ;
ErrorExit:
mov cx,[si] ;
inc si ;
inc si ;
mov dx,si ;
mov bx,1 ; write to stdout
DosInt DOS_WRITE_HANDLE ; write to that file
DosInt DOS_TERMINATE, 0
Usage:
mov si,seg DGROUP ;
mov ds,si ; load correct data segment
mov si,offset use_msg
jmp ErrorExit ;
;**********************************************************************
; program data starts
;**********************************************************************
.data
msgstruc macro msglabel, msgstring
local alpha
msglabel dw (alpha - $) - 2
db msgstring
alpha = $
endm
msgstruc err_fopen ,<"ERROR: couldn't open input file",CR,LF>
msgstruc err_fmove ,<"ERROR: unable to move file pointer",CR,LF>
msgstruc err_fread ,<"ERROR: couldn't read from input file",CR,LF>
msgstruc err_write ,<"ERROR: unable to write to floppy disk",CR,LF>
msgstruc msg_ok ,<"Boot sector was successfully written to floppy",CR,LF>
msgstruc use_msg ,<"Usage: SECTOR infile.bin",CR,LF>
buffer db SECTORSIZE dup (?) ; sector buffer
end Start