It is a really small experiment i am doing and learning. I recently went through a website called Xosdev and downloaded files for a bootsector and kernel. After exploring a little bit i wanted to compile the boot sector and initial kernel given there(it is in no way a kernel, just something to print that i have gone to protected mode). If some kernel developer out there can have a look and atleast point me towards where the mistake is, i would be ever thankful to him for giving me knowledge. I have literally broken my head on this
There are 3 files boot.asm, k_init.asm and kernel.c
k_init.asm is just having an entry point to k_main() function in kernel.c
k_main() just does the job of assigning some value to some variable, for now
Here is the code :
<snip boot.asm>
[bits 16]
[org 0x7c00]
jmp boot ; jump over the data to our code
;-----------------------Data-----------------------;
;------------GDT Table---------------;
GDTR:
GDTsize DW GDT_END-GDT-1
GDTbase DD GDT
GDT:
NULL_SEL EQU $-GDT ; null descriptor is required (64bit per entry)
DD 0x0
DD 0x0
CODESEL EQU $-GDT ; 4GB Flat Code at 0x0 with max 0xFFFFF limit
DW 0xFFFF ; Limit(2):0xFFFF
DW 0x0 ; Base(3)
DB 0x0 ; Base(2)
DB 0x9A ; Type: present,ring0,code,exec/read/accessed (10011000)
DB 0xCF ; Limit(1):0xF | Flags:4Kb inc,32bit (11001111)
DB 0x0 ; Base(1)
DATASEL EQU $-GDT ; 4GB Flat Data at 0x0 with max 0xFFFFF limit
DW 0xFFFF ; Limit(2):0xFFFF
DW 0x0 ; Base(3)
DB 0x0 ; Base(2)
DB 0x92 ; Type: present,ring0,data/stack,read/write (10010010)
DB 0xCF ; Limit(1):0xF | Flags:4Kb inc,32bit (11001111)
DB 0x0 ; Base(1)
GDT_END:
;----------End GDT Table-------------;
;------------Variables---------------;
start_s DB 0 ; starting sector [0x1-0x12]
total DB 0 ; number of sector [max 2880]
track DB 0 ; track number [max 160]
head DB 0 ; head number [max 2]
drive DB 0 ; boot drive number [usually 0]
bseg DB 0 ; memory address segment
boff DW 0 ; and offset to load into
;----------End Variables-------------;
;------------Functions---------------;
;; 'wait keyboard to clear' function ;;
wkc:
xor al,al
in al, 0x64 ; get kbd status
test al, 2 ; is bit 1 clear?
jnz wkc ; if not wait some more
ret
;; 'wait keyboard to be full' function ;;
wkf:
xor cx,cx
in al, 0x64 ; get kbd status
test al, 1 ; is bit 0 clear?
jz wkf ; if not wait some more
ret
;; 'halt on error' function ;;
halt:
mov byte [gs:0],al
mov byte [gs:1],0x04
cli
hlt
;----------End Functions-------------;
;---------------------End Data---------------------;
boot:
mov [drive],dl ; save boot drive number(0x00=floppy 0x80=hard drive)
mov ax,cs ; setup ds segment
mov ds,ax
mov es,ax
mov fs,ax
mov ss,ax ; align stack also
mov sp,0x200 ; 512 byte stack
mov ax,0xb800 ; setup video segment
mov gs,ax
jmp init ; Some BIOSes jump to 0x7c0:0x0 rather than 0x0:0x7c0
init:
;enable a20
cli
call wkc ; wait for kbd buffer to clear
mov al,0xd1 ; tell it we want to write to output port
out 0x64,al
call wkc ; wait again for kbd to clear
mov al,0xdf ; set desired settings (A20 gate)
out 0x60,al ; send value to data reg
call wkc ; wait for kbd to clear
mov cx,0x10
kbdwait:
xor ax,ax ; do anything
out 0xe0,ax ; some mor nonsense
loop kbdwait ; loop to waste time
;check if a20 was enabled
mov al,0xd0
out 0x64,al ; tell kbdc we want to read output port
call wkf ; wait for data to get in it
in al,0x60 ; get it
test al,2 ; test if A20 is on
jnz a20_on ; if it is clear, then it is off
mov al,'A' ; Error: A20 gate not enabled, halt pc
call halt
a20_on:
sti
; move GDT to 0x500
xor ax,ax
mov ds,ax
mov es,ax
mov si,GDT ; Move From [DS:SI]
mov di,[GDTbase] ; Move to [ES
I]
mov cx,[GDTsize] ; size of GDT
cld ; Clear the Direction Flag
rep movsb ; Move it
cli
;enter pmode
mov eax,cr0
or al,1
mov cr0,eax
;load gdt
lgdt[GDTR]
read:
xor ax,ax ; Floppy Reset BIOS Function
mov dl,[drive] ; Select floppy that was booted from
int 0x13
jc read
mov ax,0xffff ; Doubtful, it says 0x100000, and it is 0xffff here
mov es,ax ; Data buffer for file
mov bx,0x10 ; Start of segment
mov ah,2 ; Function to read disk
mov al,17 ; Total sectors to read
mov ch,0 ; Track
mov cl,2 ; Sector
mov dh,0 ; Head | Drive is already loaded
int 0x13 ; Call BIOS read disk function
jc read ; motor error, try again
mov ax,0xffff ; Doubtful, it says 0x100000, and it is 0xffff here
mov es,ax
mov bx, 0x2210
mov ah,2 ; Function to read disk
mov al,18 ; Total sectors to read
mov ch,0 ; Track
mov cl,1 ; Sector
mov dh,1 ; Head | Drive is already loaded
int 0x13
mov dx,0x3F2 ; stop the motor
mov al,0x0C ; from spinning
out dx,al
;clear cs/ip/eip
jmp CODESEL:FLUSH ; set cs to CODESEL
[bits 32]
FLUSH:
;refresh all segment registers
mov eax,DATASEL
mov ds,eax
mov es,eax
mov fs,eax
mov gs,eax
mov ss,eax
mov esp,0xffff
;jump to k_init.asm
jmp CODESEL:0x100000
hlt
TIMES 510-($-$$) DB 0
SIGNATURE DW 0xAA55
</snip boot.asm>
<snip k_init.asm>
[bits 32] ; 32bit code here
[global start] ; start is a global function
[extern _k_main] ; this is the kernel function
start:
call _k_main ; jump to k_main() in kernel.c
hlt ; halt the cpu
</snip k_init.asm>
<snip kernel.c>
void k_main()
{
int num =5;
/* To be modified later, first let me come here */
}
</snip kernel.c>
For compiling, i did the following
nasm -o boot.bin boot.asm
nasm -o k_init.o -f elf k_init.asm (because i can't compile it with the C code of kernel.c (ie., kernel.o ) if it is not in elf format)
gcc -Wall -W -O2 -nostdinc -fno-builtin -c kernel.c
ld kernel.o k_init.o -o kernel.bin
dd if=/dev/zero of=flp.img bs=512 count=2880
dd if=boot.bin of=flp.img conv=notrunc
dd if=kernel.bin of=flp.img seek=1 conv=notrunc
Then use bochs for booting
Everything is fine, just that, under bochs it just reboots a 100 times and fills the bochsout.txt. I feel there is something wrong while moving GDT to 0x500 step. because i have debugged using print statements and it prints till that point.
A 1000 Thanks if somebody can just point the mistake, even if it is just the compiling step (maybe i must have used a.out format !...? !!) Don't know
Thanks in advance !