I wrote my bootsector two days ago, and I am sure it is working correctly, because I've swapped other bootsectors with mine and the problem continues. So now I think the problem has to be with my kernel, whenever I make a call to any functions I get a stack fault(I wish I could provide more information but that's all vmware is throwing at me). But, I can pop & push onto the stack fine.
I get into protected mode fine, and I am passing control over to the kernel without any problems, but as soon as any function calls are made within the kernel I get a stack fault.
The bootsector is located on the first sector of the disk, and the kernel on the second.
This is my first bootsector and kernel, so sorry if the problem is obvious.
bootsector.asm
Code: Select all
;[WORD WRAP PROTECTION]------------------------------------------------------------------------------------------------------------------------
; Written By: Jeremy. A. Wildsmith
; Copyright jetaos, 2009, Jeremy. A. Wildsmith
; Main executable of the bootloader.
[BITS 16] ; Describe code is 16-bit, in real-mode, the processor runs in 16-bit mode
[ORG 0x7C00] ; Tells the assembler where the code will be in memory
; after being loaded
jmp _start
_start:
xor ax, ax ; Zero ax
mov ds, ax ; Setup data segment register to 0
mov es, ax ; Setup extra segment register.
mov [data_iBootDriveSource], dl ; Get boot source drive from dl register, and store it.
mov ebp, data_sBootMessage
call func_PrintSystemMessage ; Print system message
;Load kernel into memory
mov ebp, data_sLoadingKernelFromDisk ; Load message into ebp register
call func_PrintSystemMessage ; Print system message
mov BX, 0x1000 ; Dump to es:0x1000
mov AL, 5 ; Read 5 sectors
mov CL, 2 ; Start reading at sector 2
mov DL, byte [data_iBootDriveSource] ; Read from a drive defined in variable data_iBootDriveSource
call func_DumpSectors ; Dump selected sectors in DS:BX
mov ebp, data_sContinue ; Ask user to press any key
call func_PrintSystemMessage ; Print message
call func_WaitForKey ; Wait for keypress
mov ebp, data_sBooting ; Load message into ebp register
call func_PrintSystemMessage ; Print system message
;Load GDT
cli ; Clear interrupts
lgdt [gdt_desc] ; Load gdt
;Move processor into protected mode.
mov eax, cr0 ; Load CR0 into EAX
or eax, 1 ; Set the first bit in eax
mov cr0, eax ; Load EAX into CR0
JMP 08h:clear_pipe ; Clear pipe, setup stack and pass control to kernel
JMP $ ; Jump to current location(endless loop)
func_DumpSectors:
; Assumes:
; Data segment is setup
; BX = offset to extra segment where sector is loaded.
; AL = Number of sectors to read
; CL = Disk sector
; DL = Drive
func_DumpSectors_ResetDrive:
mov AH, 0x0 ; Call service 0
INT 0x13 ; Reset drive
jc func_DumpSectors_ResetDrive ; If carry Flag is set(reset drive failed) attempt to reset again
mov AH, 0x02 ; Service 2
mov CH, 0 ; Cylinder 0
mov DH, 0 ; Disk head
INT 0x13 ; Make call to service
jc func_DumpSectors_ResetDrive ; If carry Flag is set(read drive failed) attempt to reset again
ret ; Return to caller
jmp_BootError:
mov ebp, data_sError ; Load error message into ebp register.
call func_PrintSystemMessage ; Print message
jmp $
func_WaitForKey: ;Returns 0 for no, 1 for yes through eax register.
xor ah, ah ;Make call to service 0
INT 0x16 ;Execute interrupt 0x10
ret
func_moveCursorDown:
pushad ;Reserve Registers
;Get cursor position
mov AH, 0x03 ;Get cursor position, DH = row, DL = Col
mov BH, 0x00 ;Page #0 = graphics mode
INT 0x10 ;Execute video interrupt
;Set cursor position
inc DH ;Increment current row by one
xor DL, DL ;Reset del register(col number)
mov AH, 0x02 ;Set cursor position
mov BH, 0x00 ;Page #0 = graphics mode
INT 0x10 ;Execute video interrupt
popad ;Restore Registers
retn
func_PrintSystemMessage:
;Assumes ebp is base address of system message
push ebp ; Preserve ebp register.
mov ebp, data_sSystemPrefix ; Load ebp with system label prefix message
call func_PrintString ; Call Print Function
pop ebp ; Restore ebp register. Which is the system message
call func_PrintString ; Call print function
ret ; Return to caller
func_PrintString:
;Assume ebp contains pointer to start of string.
;$ == linedown char.
push ebp ; reserve ebp register.
@func_PrintString_loop1:
mov AL, byte [EBP] ; set al register to the character placed at ebp
cmp AL, 0 ; if AL == 0
jz func_PrintString_end1 ; return
cmp AL, '$' ; if AL != linedown Char
jne func_PrintString_print ; print character
call func_moveCursorDown ; else linedown
jmp func_PrintString_loop1_continue ; and continue loop
func_PrintString_print:
call func_PrintChar ; print char placed in al register
func_PrintString_loop1_continue:
inc EBP ; Increase ebp to move to next character
jmp @func_PrintString_loop1 ; go to start of loop
func_PrintString_end1: ; The end of the functions, all registers are
; restored to their state when callee made the call.
pop ebp ; Restore ebp register
retn ; return to caller
retn
func_PrintChar:
;Assume AL register contains ascii character to print.
;Preserve registers.
push EAX
push EBX
mov AH, 0x0E ; Service is 0x0E
mov BH, 0x00 ; Page #0
mov BL, 0x04 ; Colors
int 0x10 ; Call interrupt
;Restore registers
pop EBX
pop EAX
retn ; return to caller
[BITS 32] ;32 bit instructions for when the processor is put into protected mode.
clear_pipe: ;Assumes far jump was made to this code, at segment 0x8, which will cear the instruction pipe
mov ax, 10h ; Set AX Register to 0x10(16d), which points to the data segment
mov ds, ax ; Setup data segment
mov ss, ax ; Setup stack segment
mov esp, 090000h ; Move stack pointer to 0x90000 offset from data segment
jmp 08h:01000h ; Jmp to kernel
jmp $ ; Hang
;data, Strings are null terminated.
data_sError db 'Error booting. Reset machine.$',0
data_sLoadingKernelFromDisk db 'RD:-SEC(S:R)(2:4)1.2MB$',0
data_sBootMessage db '16\32b BL(b3.v[1.0])$',0
data_sSystemPrefix db '[SYS] ',0
data_sContinue db 'Hit enter to continue$', 0
data_sBooting db 'BL loading kern$',0
data_sInProtected db 'Exec passed to kernel(P32bit)$',0 ;P32bit = Protected 32 bit mode
data_iBootDriveSource db 0
;GDT
gdt:
gdt_null:
dq 0 ;First entry in the gdt is null, and is reserved for the processor.
;dq define quadword
gdt_code:
;DWORD1
dw 0x0FFFF ; Base is 0x0, limit is 0xFFFF. GDT Size is 0xFFFF bytes long
dw 0x0 ; No use of the last WORD
;DWORD2
db 0x0 ; First bits in base address is 0
db 10011010b ; Ring0, Is data or code|Readable, non-conforming, code segment. Segment is present
db 11001111b ; Limit 0x0F, 32bit size, 4Kb multiplier
db 0x0 ; Last bits in base address is 0
gdt_data:
;DWORD1
dw 0x0FFFF ; Base is 0(overlaps code segment) Limit is 0xFFFF
dw 0x0 ; No use of the last WORD
;DWORD2
db 0x0 ; First bits in base address
db 10010010b ; Non-conforming, writable, data segment, data or code, expands down, and is present
db 11001111b ; 32 bit, 'BIG' , LIMIT 0x0F
db 0x0 ; Last bits in the base address
gdt_end:
;GDT Descriptor
gdt_desc:
dw gdt_end - gdt ; Size of GDT
dd gdt ; Address of GDT
;NULL Memory Region + Bootloader Signature
TIMES 510 - ($ - $$) db 0 ; Fill the rest of the program with 0. $ = cur loc,
; $$ == start
; Bootloader must be 512 bytes long.
DW 0xAA55 ;Apply signature telling the bios this is a valid boot loader.
;[WORD WRAP PROTECTION]------------------------------------------------------------------------------------------------------------------------
And the kernel:
main.c
Code: Select all
int testFunc(int var)
{
return 0;
}
void main() //Kernel Entry-point
{
int i = 0;
i = testFunc(i);
while(1); //hang
}
Code: Select all
kernbase=0x1000
echo Building Kernel
gcc -ffreestanding -c main.c -o ./build/main.o
#Build twice, w\ i, unresolved externals not reported
ld -e main -Ttext $kernbase -o ./build/kernel.o ./build/main.o
ld -i -e main -Ttext $kernbase -o ./build/kernel.o ./build/main.o
objcopy -R .note -R .comment -S -O binary ./build/kernel.o ./build/kernel.bin
echo kernel build completed.