A while ago, I was writing a bootloader for my hobby OS. After a multitude of errors that I wasn't able to deal with at the time, I just gave up on it and went with GRUB, which has been working perfectly, but I want to have another try at my own bootloader. I dug up my old code, read through it, and managed to fix up a few things. However, I now have a few questions concerning what I'm meant to do immediately after entering protected mode (besides jump to my kernel).
Stage one of my bootloader does nothing but load stage two into memory at 1000h and pass control to it. My stage two bootloader, which I'll post below, enables the A20 line, loads the GDT, and enables protected mode. One thing I'm not sure about is whether the GDT loads correctly; I've used VirtualBox's debugger to dump the contents of the GDT, and it seems to have about a hundred more entries than I wanted (output is here).
My major issue is that my previous code did all of the above, then jumped to a routine called clear_pipe. The original contents of that method are here:
Code: Select all
clear_pipe:
MOV AX, 10h
MOV DS, AX
MOV SS, AX
MOV ESP, 090000h
MOV BYTE [DS:0B8000h], 'P'
MOV BYTE [DS:0B8001h], 1Bh
Thanks for the time. Here's the current contents of the stage two file (doesn't include the stuff in clear_pipe, as I rewrote the file):
Code: Select all
org 1000h
bits 16 ; 16 bits, as this is a bootloader
%include "enableA20.s" ; contains our routine for enabling the a20 line
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; start.asm: stage 2 of our bl. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
start:
push cs
pop ds ; segments out of order, fix it up
call check_a20 ; check if a20 is enabled
cmp ax, 0 ; compare AX to 0 for error
je enableA20 ; enable the a20 line
call check_a20 ; check again
cmp ax, 0 ; error check
je hang_error ; hang with error message
cli ; clear interrupts for gdt
lgdt[gdt_desc] ; load the gdt
mov eax, cr0 ; get cr0
or eax, 1 ; set the first bit in cr0
mov cr0, eax ; welcome to pmode
jmp 08h:clear_pipe ; jump to clear
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Check if A20 is enabled
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
check_a20:
pushf
push ds
push es
push di
push si
cli
xor ax, ax
mov es, ax
not ax
mov ds, ax
mov di, 0x0500
mov si, 0x0510
mov al, byte [es:di]
push ax
mov al, byte [ds:si]
push ax
mov byte [es:di], 0x00
mov byte [ds:si], 0xFF
cmp byte [es:di], 0xFF
pop ax
mov byte [ds:si], al
pop ax
mov byte [es:di], al
mov ax, 0
je check_a20_exit
mov ax, 1
check_a20_exit:
pop si
pop di
pop es
pop ds
popf
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Address for GDT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdt:
gdt_null:
dd 0
dd 0
gdt_code:
dw 0FFFFh
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data:
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end:
gdt_desc:
dw gdt_end - gdt - 1
dd gdt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Prints to the screen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
print:
pusha ; Push all pointers and standard registers
mov ah, 0eh ; set ah to 0eh (this is an 'argument' for int 10h)
.loop:
lodsb
test al, al ; Make sure al is not zero (zero-terminated string)
jz .end
int 10h ; Print contents of al
jmp .loop
.end:
popa ; Restore registers
ret ; Return to previous instruction
hang_error:
mov si, msg_a20
jmp hang
hang:
jmp hang ; Hang indefinitely
msg_a20 db 'Error while enabling A20', 13, 10, 0
bits 32 ; pmode is 32-bit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; clear stuff, print a p to the screen (???)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
clear_pipe:
jmp hang_two
hang_two:
jmp hang_two