Bootloader issue; int 13h succeeds but jump fails
Posted: Sun Mar 28, 2010 9:00 am
I have been writing stage1 of a three-stage bootloader for the past couple of days and for the past two, I've been trying to figure out why nothing happens when I try to jump to stage2.
I set up a stack and do some other setup stuff:
[NASM syntax]
and then, 1k is fetched from the boot disk (at compile-time, my Makefile creates a 1.44MB .img file):
but after the last message is printed ("plxls1: stage2 loaded, run stage2..."), nothing happens.
Full code:
stage1/plxs1.asm:
include/rmode/screen.asm:
include/rmode/diskio.asm:
stage2/main.c:
I'm not sure why "Hello, world!" is not printed to the screen. I've tried a lot of different things like changing parameters to readsectors and things, but nothing has worked. If you need to to see anything else, it's yours, my friend; as long as you have enough rubies.
[I think this goes here; it's related to OS development, but it isn't an OS.]
I set up a stack and do some other setup stuff:
[NASM syntax]
Code: Select all
;==============================================================================;
; _start: do some initialization and then call main
_start:
.setup:
cli
; Zero AX, DS, SS
xor ax, ax
mov ds, ax
mov ss, ax
; Set up the stack
mov ax, 0x9c00
mov sp, ax
; Store the boot disk
mov [bootdisk], dl
sti
.load:
call main
jmp hang ; Hang the machine should main return
;------------------------------------------------------------------------------;
Code: Select all
; main: find and load stage2
main:
print "plxls1: load stage2...", 13, 10, 0
; Load sectors from disk
mov al, 4 ; Read some sectors
mov cx, 2 ; Start from sector 2, cylinder 0
xor dh, dh ; Read from head 0
mov dl, [bootdisk]
; Set up the buffer
mov bx, 0x1000
mov es, bx
xor bx, bx ; Data will be loaded at [ES:BX] == 1000h:0000h
call readsectors
print "plxls1: stage2 loaded, run stage2...", 13, 10, 0
; Far jump to stage2
jmp 0x1000:0x0000
ret
;------------------------------------------------------------------------------;
Full code:
stage1/plxs1.asm:
Code: Select all
;==============================================================================;
; plxls1.asm: main file for stage1; finds and loads stage2 ;
;==============================================================================;
;==============================================================================;
%ifndef _PLXLS1_ASM
%define _PLXLS1_ASM
;------------------------------------------------------------------------------;
[bits 16]
[org 0x7c00]
jmp _start
;------------------------------------------------------------------------------;
%include "rmode/screen.asm"
%include "rmode/diskio.asm"
;==============================================================================;
;==============================================================================;
; _start: do some initialization and then call main
_start:
.setup:
cli
; Zero AX, DS, SS
xor ax, ax
mov ds, ax
mov ss, ax
; Set up the stack
mov ax, 0x9c00
mov sp, ax
; Store the boot disk
mov [bootdisk], dl
sti
.load:
call main
jmp hang ; Hang the machine should main return
;------------------------------------------------------------------------------;
; main: find and load stage2
main:
print "plxls1: load stage2...", 13, 10, 0
; Load sectors from disk
mov al, 4 ; Read some sectors
mov cx, 2 ; Start from sector 2, cylinder 0
xor dh, dh ; Read from head 0
mov dl, [bootdisk]
; Set up the buffer
mov bx, 0x1000
mov es, bx
xor bx, bx ; Data will be loaded at [ES:BX] == 1000h:0000h
call readsectors
print "plxls1: stage2 loaded, run stage2...", 13, 10, 0
; Far jump to stage2
jmp 0x1000:0x0000
ret
;------------------------------------------------------------------------------;
; hang: hang the machine indefinitely
hang:
cli
.halt:
hlt
jmp .halt
;==============================================================================;
;==============================================================================;
bootdisk: db 0x00
times 510 - ($ - $$) db 0x00
bootsignature: dw 0xaa55
;==============================================================================;
%endif ; ! _PLXLS1_ASM
Code: Select all
;==============================================================================;
; screen.asm: access to screen-related functions such as putchar ;
;==============================================================================;
;==============================================================================;
%ifndef _SCREEN_ASM
%define _SCREEN_ASM
;------------------------------------------------------------------------------;
[bits 16]
;------------------------------------------------------------------------------;
%macro print 1+
jmp %%do_print
%%str:
db %1, 0
%%do_print:
mov si, word %%str
call putstr
%endmacro
;==============================================================================;
;==============================================================================;
;------------------------------------------------------------------------------;
; putchar: put a character on the screen
; @AL: the character to print
putchar:
mov ah, 0x0E
int 0x10
ret
;------------------------------------------------------------------------------;
; putstr: print a NULL-terminated ASCII string to the screen. The string should
; be pointed to by SI
putstr:
.next_char:
; Load the character
lodsb
; Check it to see if it's NUL (EOL marker)
cmp al, 0
je .done ; AL == 0: done
; Print the char if AL != 0
call putchar
jmp .next_char
.done:
ret
;==============================================================================;
%endif ; ! _SCREEN_ASM
Code: Select all
;==============================================================================;
; diskio.asm: access to the disk through the BIOS ;
;==============================================================================;
;==============================================================================;
%ifndef _DISKIO_ASM
%define _DISKIO_ASM
;------------------------------------------------------------------------------;
[bits 16]
;==============================================================================;
;==============================================================================;
; readsectors: read sectors from disk
; @AL: sector count
; @CH: starting track
; @CL: starting sector
; @DH: head/side no.
; @DL: drive no.
; @ES:BX: buffer
; Returns 0 in AL on success, or 1 on error
;
; NOTE: Due to some BIOS' limitations, we have to read one sector at a time.
readsectors:
mov [count], al
.read:
call resetdisk
mov ah, 0x02
mov al, 0x01
int 0x13
jnc .check ; CF is 0 if the read succeeded
print "disk read error", 13, 10, 0
jmp .read ; CF is not 0: error; try again without changing count
.check:
dec byte [count]
cmp byte [count], 0
je .done ; count = 0: no more sectors left
jmp .read ; read more secotrs
.done:
ret
;------------------------------------------------------------------------------;
; resetdisk: reset a disk
; @DL: drive no.
; Returns 0 in AL on success, or 1 on error
resetdisk:
xor ah, ah
int 0x13
jnc .done ; CF is 0 if the read succeeded
print "disk reset error", 13, 10, 0
jmp resetdisk
.done:
ret
;==============================================================================;
;==============================================================================;
count: db 0
;==============================================================================;
%endif ; ! _DISKIO_ASM
Code: Select all
int main()
{
asm("cli");
char* buffer = "Hello, world!",
* vmem = (char*)0xB8000;
while (*buffer) {
*vmem++ = *buffer++;
*vmem++ = 0x07;
}
for (;;)
asm("hlt");
return 0;
}
[I think this goes here; it's related to OS development, but it isn't an OS.]