Saturday, November 11, 2006

Now it is one step ahead

A little kernel (sorry it is not right to call it a kernel) program that goes to protected mode, and prints a string. Done using nasm and c . Here it is

%define CS_ACCES 10011011b
%define DS_ACCES 10010011b
[bits 16]
[org 0x0] ; Begins at 0x0:Whatever you define next

jmp boot

%include "GDT.INC"

mov ax,0x07C0 ; Define the beginning of boot at 0x0000:0x07c0
mov ds,ax
mov es,ax
mov ax,0x8000 ; Define Stack
mov ss,ax
mov sp,0xf000 ; Stack begins at 0xf000 and fills from there

; Read the kernel binary from floppy to your memory location
; at 0x100:0x0000
; In real mode 0x7c00 = 0x7c0:0 or 0x7c0:0 = 0x07c0 shifted left once + 0
; so 0x1000 = 0x100:0 = 0x0100 shifted left once + 0
; 0x1000 = es, 0x0000 = bx
; First restart the motor

xor ax,ax
int 0x13

push es ; es has stack defined

mov ax,0x100
mov es,ax
mov bx,0

mov ah,2
mov al,30
mov ch,0
mov cl,2
mov dh,0
mov dl,0
int 0x13

pop es; Now es holds stack addresss

; Fill in the GDT now, before doing the lgdt
; Because GDT is all 0's now

descInit 0,0xFFFFF,CS_ACCES,1101b,gdt_cs
descInit 0,0xFFFFF,DS_ACCES,1101b,gdt_ds

; Before doing lgdt, we must supply two parameters to lgdt
; One is the limit, and the other is the linear address of GDT
; Refer to the GDT structure below

; Size of gdt = gdtend - gdt

mov ax, gdtend
mov bx, gdt
sub ax,bx
mov word [gdtptr], ax

; Linear address

xor ax,ax ; Clear eax
mov ax,ds ; Move segment 0x7c0 to ax
mov bx,gdt; Move offset to bx
call calcadr; Calculate linear address and store it in ecx
mov dword [gdtptr+2], ecx ; Move it to gdtptr

; Load gdt using lgdt. Disable interrupts before that


; Move to protected mode. Set cr0's first bit to 1 by oring it

mov eax,cr0
or ax,1
mov cr0,eax

; Re define segments and offsets in protected mode
; cs -> as defined by gdt ie., using jmp instruction
; Define ds -> as the pointer to the data segment register's
; displacement with gdt, ie 0x10

jmp next

mov ax,0x10
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax ; Stack also begins at data segment

mov esp,0x9f000 ; Stack begins filling at this address

; code segment pointed by cs register at a displacement of 0x8 bytes
; from the beginning of gdt
; Now jump to the location of kernel binary w.r.t. code segment

; protected mode segmented address = cs:0x1000

jmp dword 0x8:0x1000

jmp end ; Just in case it slips the earlier step !

; Definition of Zeroed out GDT
; GDT initially has 0's in all places
; GDT has 3, 8 byte segment descriptors defined
; The three are, NULL, Code segment and Data segment descriptor
; Remember the following are all variables

dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0

; gdtptr is supposed to be passed to lgdt. It has been zeroed in the beginning

dw 0x0000 ; 16 bit size of GDT
dd 0 ; 32 bit linear address of GDT

; Fill the rest of 510 bytes with NOP (0x144)

times 510-($-$$) db 144

dw 0xaa55 ; The signature of boot sector

void _start(void) {

int main(void){
unsigned char *video = (unsigned char *) 0xb8000;

char *string = "Kernel loaded";

while (*string !=0)
*video = *string;
*video = 0x07;

compile as

nasm -f bin -o boot boot.asm

gcc -w -c kernel.c -o kernel.o
ld -Ttext 0x1000 --oformat binary kernel.o -o kernel

cat boot kernel >

use bochs and boot