I tried to make a bootloader the last few days and this is the result:
BITS 16
;CONSTANTS
BOOTSEG equ 07C0h
STACKSEG equ 1BC0h ; BOOTSEG + 512 Byte (bootloader) + 512 Byte (second stage) + 4096 Byte (buffer) = 1BC0h
STACKSIZE equ 0400h ; 1KB stack
; INIT
mov AX, BOOTSEG
mov DS, AX ; set data segment to adress where bootloader will be loaded to
mov AX, STACKSEG
cli ; disable interrupts while set up stack
mov SS, AX
mov SP, STACKSIZE ; set up stack
sti ; restore interrupts
mov [bootdev], DL ; save boot device number
;START
mov SI, string ; get the adress of the string to print into SI
call _printstring
;LOAD 2nd STAGE
mov AH, 02h ; int 13h subfunction ah=02
mov AL, 01h ; read 1 sector
mov CX, 02h ; begin read at track 0, sector 2
mov DH, 00h ; head = 0 ????
mov DL, [bootdev] ; read from boot device
mov BX, BOOTSEG
add BX, 512
mov ES, BX ; write second stage right after first stage
mov BX, 00h
int 13h ; do it
jc fail
mov SI, success ; OK
call _printstring
jmp 09C0h:0000h ; jump to second stage, execute it
; does not work:
; 1) jmp ES:BX
;
; 2) push ES
; push BX
; retf
fail:
mov SI,error ; error on reading second stage
call _printstring
loop:
jmp loop ; infinite loop at the end
_printhex:
; AX: hex value to print
; Modifies: AX, BX, DX, CX
mov CX, 4
start: mov DX, 00h
mov BX, 10h
div BX
cmp DX, 9
jg letter
add DL, 30h
jmp store
letter: add DL, 37h
store: push DX
dec CX
jnz start
mov CX,4
print: pop AX
call _printchar
dec CX
jnz print
mov AL, 13
call _printchar
mov Al, 10
call _printchar
ret
_printchar:
; print char in AL
; Modifies: AX, BX
mov AH, 0Eh
mov BX, 07h
int 10h
ret
_printstring:
; SI : start adress of string
; Modifies: AX , BX , SI
m1: lodsb ; Loads [SI] into AL and increases SI by one
or AL, AL ; check if AL = 0
jz finish ; then finish
call _printchar ; else print charakter
jmp m1
finish:
ret ; return from the printstring call
;DATA
string db 'Started my first Bootloader', 13, 10, 0
success db 'Success', 13, 10, 0
error db 'Error', 13, 10, 0
bootdev db 0
; MAKE BOOTSECTOR
times 510-($-$$) db 0 ; fill up the sector to 512 - 2 = 510 bytes
dw 0AA55h ; set the two bootsector identifying bytes
; SECOND STAGE
add BX, 10
mov AL, 'A'
mov AH, 0Eh
mov BX, 07h
int 10h ; test output
loop2:
jmp loop2 ; infinite loop at the end
Now I have two questions:
In line 43 I have to use a jump with an absolute adress, but I want to use the values of ES
and BX
. So I tried the two alternatives you can see in the comments but they did not work for me. What am I doing wrong?
I am quite new to low-level programming. Are there some major or minor mistakes in my code? Are there code style conventions I did not consider?
I do not want to format the code, so here is the link to the asm file and you can read it with your favourite editor: https://www.dropbox.com/s/i3jpprf66nlmzz2/mybootloader.asm?m
jmp 09C0h:0000h
and
push ES
push BX
retf
should work equally well (provided, of course, ES
=9C0h and BX
=0 in the latter case).
And jmp ES:BX
is not a valid instruction, or, at least, it's not going to do what you might be expecting from it.
Possible problems:
I found the bug. A very silly mistake: The BX register was overwritten by the _printstring function bevor the interrupt was triggered. I fixed it and now the jump does exactly work like described by Alexey Frunze - thank you:
push ES
push BX
retf
Moreover I´ve made a mistake in segment adressing (also thanks to Alexey Frunze): I wanted to load the second stage right after the 512 byte long first stage. So referring to segment/offset adressing (physical adress = 16*segment + offset) I have to add 512/16 = 32 = 20H to 07C0. So the values have to be: ES = 07E0H and BX = 0000H
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.