Page 1 of 1

Trouble with my bootsector =/

Posted: Sun Mar 23, 2008 2:42 pm
by White-spirit
Hello all,

I started to learn to create a personal OS ( just a little boot loader and a 32 bits kernel ^_^ ), but i have a problem with my boot sector, it reboots on the 29th line ( mov ax,10h ) .

Who can help me please ? Here's my code ( inspired from Gregor Brunmar's tutorial ) :

Code: Select all

[BITS 16]
[ORG 0x7C00]

push es
mov ax, 0x1000
mov es, ax
mov bx, 0      
mov ah, 2
mov al, 2				; 2 sectors in case when the Kernel becomes too big
mov ch, 0
mov cl, 2
mov dh, 0
int 13h                 ; Interrupt 13h
pop es

cli

xor ax,ax
mov ds,ax

lgdt [gdt_desc]

mov eax,cr0
or	eax,1
mov cr0,eax
jmp dword 08h:load_kernel

[BITS 32]
load_kernel:
mov ax,10h ; [FR] Ne cesse pas de redemarrer ici ... [EN] Reboots here ...
jmp $
mov ds,ax
mov ss,ax
mov esp, 0x90000

jmp dword 08h:0x1000
jmp $

gdt:

gdt_null:
dw 0
dw 0
	
gdt_code:
dw 0xFF
dw 0
db 0
db 0x9A
db 0xCF
db 0
	
gdt_data:
dw 0FFFFh
dw 0
db 0
db 0x92
db 0xCF
db 0
	
gdt_end:

gdt_desc:
dw gdt_end - gdt - 1
dd gdt
	
times 510-($-$$) db 144		; Fills the file with NOP's
dw 0xAA55

Re: Trouble with my bootsector =/

Posted: Sun Mar 23, 2008 3:37 pm
by Dex
Try this

Code: Select all

[BITS 16]
[ORG 0x7C00]

push es
mov ax, 0x1000
mov es, ax
mov bx, 0      
mov ah, 2
mov al, 2				; 2 sectors in case when the Kernel becomes too big
mov ch, 0
mov cl, 2
mov dh, 0
int 13h                 ; Interrupt 13h
pop es

cli

xor ax,ax
mov ds,ax

lgdt [gdt_desc]

mov eax,cr0
or	eax,1
mov cr0,eax
jmp dword 08h:load_kernel

[BITS 32]
load_kernel:
mov ax,10h ; [FR] Ne cesse pas de redemarrer ici ... [EN] Reboots here ...
jmp $
mov ds,ax
mov ss,ax
mov esp, 0x90000

jmp dword 08h:0x1000
jmp $

gdt:

gdt_null:                      ;<********See here***********
dw 0			           ; (0h) Null Segment
dw 0
db 0
db 0
db 0
db 0			           ;<*********Too here**********
	
gdt_code:
dw 0xFF
dw 0
db 0
db 0x9A
db 0xCF
db 0
	
gdt_data:
dw 0FFFFh
dw 0
db 0
db 0x92
db 0xCF
db 0
	
gdt_end:

gdt_desc:
dw gdt_end - gdt - 1
dd gdt
	
times 510-($-$$) db 144		; Fills the file with NOP's
dw 0xAA55

Posted: Sun Mar 23, 2008 4:17 pm
by Combuster
a GDT entry is 8 bytes - your first entry is only four (two words instead of two doublewords)

try:

Code: Select all

GDT.null:
DD 0
DD 0

Posted: Mon Mar 24, 2008 3:27 am
by Ready4Dis
Combuster wrote:a GDT entry is 8 bytes - your first entry is only four (two words instead of two doublewords)

try:

Code: Select all

GDT.null:
DD 0
DD 0
Try this, I don't know why people like to waste the memory in their boot loader, or why everyone thinks because it's called a NULL descriptor that it must be NULL, this is not the case. You can put the gdt descriptor in that memory space to save a few bytes, and if you'r really worried you can even use that last 2-bytes in the null descriptor to hold a variable or two, just make sure you don't mess up the size of the descriptor. The CPU does not use the NULL descriptor, it is only a space filler. If cs,ds,es is 0, it will throw an exception no matter what is in the descriptor.

Code: Select all

gdt:
gdt_null:                      ;Yay, i'm not emptry anymore, i have a purpose
gdt_desc:
dw gdt_end - gdt - 1
dd gdt
dw 0

gdt_code:
dw 0xFFff
dw 0
db 0
db 0x9A
db 0xCF
db 0
   
gdt_data:
dw 0FFFFh
dw 0
db 0
db 0x92
db 0xCF
db 0   
gdt_end:
This saves you 6 bytes in your boot loader, possibly 8 if you use the other 2 for a variable ;).

Posted: Mon Mar 24, 2008 5:00 am
by White-spirit
Ready4Dis wrote:
Combuster wrote:a GDT entry is 8 bytes - your first entry is only four (two words instead of two doublewords)

try:

Code: Select all

GDT.null:
DD 0
DD 0
Try this, I don't know why people like to waste the memory in their boot loader, or why everyone thinks because it's called a NULL descriptor that it must be NULL, this is not the case. You can put the gdt descriptor in that memory space to save a few bytes, and if you'r really worried you can even use that last 2-bytes in the null descriptor to hold a variable or two, just make sure you don't mess up the size of the descriptor. The CPU does not use the NULL descriptor, it is only a space filler. If cs,ds,es is 0, it will throw an exception no matter what is in the descriptor.

Code: Select all

gdt:
gdt_null:                      ;Yay, i'm not emptry anymore, i have a purpose
gdt_desc:
dw gdt_end - gdt - 1
dd gdt
dw 0

gdt_code:
dw 0xFFff
dw 0
db 0
db 0x9A
db 0xCF
db 0
   
gdt_data:
dw 0FFFFh
dw 0
db 0
db 0x92
db 0xCF
db 0   
gdt_end:
This saves you 6 bytes in your boot loader, possibly 8 if you use the other 2 for a variable ;).
Thanks, it works =)

Now, i have a problem with my kernel, it reboots also x')

Code: Select all

void gotoxy ();
void clrscr ();
void print (char*);

int kernel_main(void)
{
	clrscr();
	print("Premier message\n");
	print("Deuxiéme message\n");
	while(1);
	return(0);
}

int x=0;
int y=0;

void gotoxy (unsigned int Nx,unsigned int Ny){
	x=Nx;
	y=Ny;
}
void clrscr (){
	int i;
	unsigned char* screen=(unsigned char *)0xB8000;
	for (i=0;i<80*25;i++){
		*screen++=0x0;
		*screen++=0x07;
	}
}
			
void print( char* chaine )
{
	unsigned char *screen = (unsigned char *)0xB8000;

	int pos=0;
	int i = 0;
	
	while ( chaine[i] != '\0' )
	{
		screen[pos++] = chaine[i++];
		screen[pos++] = 0x07;
	}
}
For compiling/linking , i use :

Code: Select all

nasm -f bin bootsector.asm -o bootsector.bin

gcc -ffreestanding -c kernel.c -o kernel.o

ld -e kernel_main -Ttext 0x1000 -o kernel kernel.o
objcopy -R .note -R .comment -S -O binary kernel kernel.bin

cat bootsector.bin kernel.bin /dev/zero | dd of=a.img bs=512 count=2880
It's due to a little mistake in the kernel code or it's an issue with my compiling/linking instructions ?

Thanks .

Posted: Mon Mar 24, 2008 5:13 am
by 01000101
I didn't really look at the code at all, but your problem is a little vague. Do you have a BOCHS dump? where does it reboot? if it is right off the bat, then you probably are jumping to the wrong memory address from your bl.

Posted: Mon Mar 24, 2008 5:22 am
by White-spirit
01000101 wrote:I didn't really look at the code at all, but your problem is a little vague. Do you have a BOCHS dump? where does it reboot? if it is right off the bat, then you probably are jumping to the wrong memory address from your bl.
I don't know what you do mean with the BOCHS dump, but here's what i see in the Bochs Console :

Code: Select all

00022224010i[APIC0] local apic in CPU 0 initializing
00022227750i[BIOS ] $Revision: 1.160 $ $Date: 2006/01/25 17:51:49 $
00022542067i[KBD  ] reset-disable command received
VGABios $Id: vgabios.c,v 1.63 2005/12/26 19:50:26 vruppert Exp $
00022651081i[CLVGA] VBE known Display Interface b0c0
00022651113i[CLVGA] VBE known Display Interface b0c3
00022654038i[VBIOS] VBE Bios $Id: vbe.c,v 1.48 2005/12/26 19:50:26 vruppert Exp
$
00022978693e[HD   ] ata0: device set to 0 which does not exist
00022978986e[HD   ] ata0: device set to 1 which does not exist
00022979278e[HD   ] ata1: device set to 0 which does not exist
00022979571e[HD   ] ata1: device set to 1 which does not exist
00023149993e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00023149993e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00023149993e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00023149993i[CPU0 ] protected mode
00023149993i[CPU0 ] CS.d_b = 32 bit
00023149993i[CPU0 ] SS.d_b = 32 bit
00023149993i[CPU0 ] | EAX=c08e1002  EBX=02b40000  ECX=00000002  EDX=00000000
00023149993i[CPU0 ] | ESP=0008fffc  EBP=00000000  ESI=00007343  EDI=0000ffde
00023149993i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00023149993i[CPU0 ] | SEG selector     base    limit G D
00023149993i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00023149993i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00023149993i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00023149993i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00023149993i[CPU0 ] |  ES:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00023149993i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00023149993i[CPU0 ] |  GS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00023149993i[CPU0 ] | EIP=00007c15 (00007c15)
00023149993i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00023149993i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00023149993i[CPU0 ] >> int 0x13 : CD13
00023149993e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown
 status is 00h, resetting
00023149993i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called

Posted: Mon Mar 24, 2008 5:39 am
by White-spirit
Yes ! I've found the bug, i changed this :

Code: Select all

push es
mov ax, 0x1000
mov es, ax
mov bx, 0     
mov ah, 2
mov al, 2				; 2 sectors in case when the Kernel becomes too big
mov ch, 0
mov cl, 2
mov dh, 0
mov dl, 0
int 13h                 ; Interrupt 13h
pop es
by :

Code: Select all

push es
mov ax, 0
mov es, ax
mov bx, 0x1000      
mov ah, 2
mov al, 2				; 2 sectors in case when the Kernel becomes too big
mov ch, 0
mov cl, 2
mov dh, 0
mov dl, 0
int 13h                 ; Interrupt 13h
pop es
Thanks all =)

Posted: Mon Mar 24, 2008 5:41 am
by Ready4Dis
Well, firstly, you are linking your text area at 0x1000. You're loading your bootsector at es:si, or 0x1000:0x0000, which is linear address 0x10000, so you need to be linking to 0x10000 instead of 0x1000. Also, do a hex-view of your kernel and make sure that your main function is the FIRST thing in the file (it may be running the wrong piece of code, or trying to run a text string rather than your main function). Typically I use an ASM stub in my kernel and link it to my C code, my ASM stub then jumps to my kernel's main function. This means I don't have to worry about data being put before my startup function, because my asm stub is always the first thing linked, so my main function can be located anywhere within the program. Also, instead of doing while (1), it's typical to use for (;;);, because some compilers will actually do
again:
mov ax, 1
cmp ax,1
je again

Where a for (;;); is typically just:
.j jmp .j, or
again:
jmp again


I think nowadays it's mostly habbit, because a smart compiler should know what to do with while (1);

Posted: Mon Mar 24, 2008 7:36 am
by 01000101
because of the structure of my OS, I have a pseudo-start function that just pushes the jump to my kernel a little farther to the actual main() function.


you might actually want to consider NOT using C to test if your bl is jmping to your kernel, you might want to use ASM and put a hlt with a trivial one-liner after the hlt to see if you are running the right code or not