And this is my problem: My bootloader will load stage 2, then stage 2 load the kernel. Everything work just fine, except for I get absolutely no output to the screen.
This is my bootloader:
Code: Select all
ORG 0x7c00
jmp 0x0000:start ; sync weird bios segment:offset pairs on bootup
start:
cli ; disable interrupts until we enter unreal mode
xor ax, ax ; zero all the segment registers
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov byte [drvnum] , dl ; save the boot device ID in the FAT BPB
enable_a20_fast: ; use the fast method to enable A20 gate access
in al, 0x92
or al, 0x02
out 0x92, al
init_stack:
mov esp, 0x7C00 ; set up our stack to 0x7C00
mov bp, sp
sti
;load stage2
reset:
MOV AH, 0
MOV DL, [drvnum]
INT 0x13
JC reset
MOV AH, 0x02
MOV AL, 4
MOV CH, 0
MOV CL, 0x02
MOV DH, 0
MOV DL, [drvnum]
MOV BX, 0x7E0
MOV ES, BX
MOV BX, 0
INT 0x13
JC reset
;MOV AX, 0x7E0
;MOV DS, AX
MOV AH, byte [drvnum]
MOV AL, 0
PUSH AX
JMP 0x7E0:0000
drvnum DB 0
times 510-($-$$) db 0
dw 0xAA55
Code: Select all
ORG 0x7E00
POP AX
MOV byte [drvnum], AH
;load kernel
reset:
LEA SI,[msg]
call print
MOV AH, 0
MOV DL, [drvnum]
INT 0x13
JC reset
MOV AH, 0x02
MOV AL, 25
MOV CH, 0
MOV CL, 0x06
MOV DH, 0
MOV DL, [drvnum]
MOV BX, 0x1000
MOV ES, BX
MOV BX, 0
INT 0x13
JC reset
MOV AX, 0x0
MOV DS, AX
jmp enter_pmode
jmp $
print:
LODSB
OR AL, AL
JZ done
MOV AH, 0x0E
INT 0x10
JMP print
done:
ret
drvnum DB 0
msg DB "Running Stage 2 ...", 13, 10, 0
; ========================================
enter_pmode: ; leave unreal mode, and enter PMode]
cli ; no more interrupts for us!
lgdt [GDT_SEL] ; load the GDT
mov eax, cr0
or al, 1 ; turn on protection in CR0
mov cr0, eax
jmp 0x08:pmode ; far jump to set CS to 0x08 (GDT:CODE32)
[BITS 32]
pmode:
cli
mov eax, 0x10 ; set segment registers to 0x10 (DATA32)
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
call parse_elf ; get info about kernel.elf
mov esp, 0x7C00
mov ebp, esp
xor ebx, ebx
xor ecx, ecx
xor edx, edx
xor esi, esi
xor edi, edi
mov eax, dword [ENTRY] ; EAX = elf entry point
call eax ; jump to our kernel
ENTRY dd 0
; ========================================
parse_elf:
pusha
mov ebx, 0x10000 ; EBX = where kernel.elf starts
mov eax, ebx ; EAX = EBX
add ebx, 24 ; offset to EH->ENTRY (24)
mov edx, dword [ebx] ; EDX = EH->ENTRY
mov dword [ENTRY], edx ; save the value
add ebx, 4 ; offset to EH->PH_OFF (28)
add eax, dword [ebx] ; EAX = EH->PH_OFF
add ebx, 16 ; offset to EH->PH_NUM (44)
mov cx, word [ebx] ; CX = EH->PH_NUM
mov ebx, eax ; EBX = EH->PH_OFF + 0x10000
.find_type:
push ecx ; save ECX
push ebx ; save where we are
mov eax, 0x01 ; EAX = PH_TYPE_LOAD
cmp eax, dword [ebx] ; if the PH->TYPE == PH_TYPE_LOAD, copy the addresses
jne .skip
add ebx, 4 ; offset to PH->OFFSET
mov esi, dword [ebx] ; ESI = PH->OFFSET
add esi, 0x10000 ; ESI += where the kernel.elf is loaded (0x10000)
add ebx, 8 ; offset to PH->PHYSADDR
mov edi, dword [ebx] ; EDI = PH->PHYSADDR
add ebx, 8 ; offset to PH->MEMSIZE
mov ecx, dword [ebx] ; ECX = PH->MEMSIZE
rep movsb ; memcopy!
.skip:
pop ebx ; restore the start of the header
add ebx, 32 ; skip to the next
pop ecx ; restore ECX
dec cx ; counter--
cmp cx, 0 ; if the counter has reached 0, we're done
jna .done ; else, keep parsing headers
jmp .find_type
.done:
popa
ret
; ========== GDT Segment Selector ==========
align 4
GDT_SEL:
dw GDT_DESC_END-GDT_DESC-1
dd GDT_DESC
; ========== GDT Segment Descriptor ==========
align 8
GDT_DESC:
.NULL:
dq 0x0000000000000000 ; null segment
.CODE32:
dq 0x00CF9A000000FFFF ; limit = 4GB, D/B = 32-bit, DPL = 0, type = code r/w
.DATA32:
dq 0x00CF92000000FFFF ; limit = 4GB, D/B = 32-bit, DPL = 0, type = data r/w
GDT_DESC_END:
TIMES 2048-($-$$) db 0
Hope that I will get some good answers...