Trouble with my bootsector =/

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
White-spirit
Member
Member
Posts: 89
Joined: Sun Mar 23, 2008 2:23 pm
Location: [0x8:0x1000]

Trouble with my bootsector =/

Post 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
Last edited by White-spirit on Thu Dec 01, 2011 5:42 am, edited 1 time in total.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: Trouble with my bootsector =/

Post 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
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post 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
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Ready4Dis
Member
Member
Posts: 571
Joined: Sat Nov 18, 2006 9:11 am

Post 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 ;).
White-spirit
Member
Member
Posts: 89
Joined: Sun Mar 23, 2008 2:23 pm
Location: [0x8:0x1000]

Post 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 .
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Post 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.
White-spirit
Member
Member
Posts: 89
Joined: Sun Mar 23, 2008 2:23 pm
Location: [0x8:0x1000]

Post 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
White-spirit
Member
Member
Posts: 89
Joined: Sun Mar 23, 2008 2:23 pm
Location: [0x8:0x1000]

Post 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 =)
Ready4Dis
Member
Member
Posts: 571
Joined: Sat Nov 18, 2006 9:11 am

Post 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);
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Post 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
Post Reply