jmping to kernel...

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
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

jmping to kernel...

Post by suthers »

Im a bit confused, once my bootloader has activated A20, read my kernel and past into 32-bit mode, what are the steps I have to take to pass control to my kernel?
(also I load my kernel at 0x7e00 I was wondering if this was a good idea or not?)
Thanks in advance,

Jules
davidv1992
Member
Member
Posts: 223
Joined: Thu Jul 05, 2007 8:58 am

Post by davidv1992 »

assuming your kernel is in the memory as executable code (so properly linked and relocated (if aplicable)) and you know the adres of the entry point the only thing you have to do is jump straight in it. You could however use your bootloader to gain system information from the bios, but that is an action to do before going into pmode.

Loading at 0x7e00 gives some problems as that if you're bootloader doesn't relocate itself to a safe location, it will be overwritten in the proces, which can cause nasty results
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

Post by suthers »

0x7e00 is exactly 512 bytes after 0x7c00, so i don't think anything should be overwritten.
I do a jump:
0x7e00:0x0000
But vmware says that there was a stack error in kernel mode.
don't know how to fix this.
Any ideas?
Thanks in advance,
Jules

P.S. yes i have loaded it, but isn't there something you have to do to set up a segment?
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

try this:

Code: Select all

jmp 0x08:0x7e00
Make sure that your code segment is the 2nd GDT entry (hence 0x08).
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
suthers wrote:0x7e00 is exactly 512 bytes after 0x7c00, so i don't think anything should be overwritten.
Where's your stack (and ".bss" section)?

If your boot loader is only 512 bytes (less the BPB and/or partition table) then you're doing something wrong, like only loading one sector of the kernel (when you know the kernel will grow to more than that) and not having decent error handling (for e.g. I'm currently using about 270 bytes for ASCIIZ strings for BIOS error messages alone).
suthers wrote:I do a jump:
0x7e00:0x0000
I thought you were in 32-bit protected mode (doing "0x7e00:0x0000" looks like something you'd do if you were in real mode).

For protected mode, the value you load into CS (using the "jmp far") is an entry in the GDT. For example, "jmp 0x7E00:0x0000" would jump to the code segment described by GDT entry number 0xFC0 (at offset 0x7E00 in the GDT).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
nekros
Member
Member
Posts: 391
Joined: Wed Mar 05, 2008 9:10 pm
Contact:

Post by nekros »

only problem with loading at 0x7E00 is that if your kernel gets large enough you might overwrite video memory and when you write to video memory you will overwrite some of your kernel, when you execute the code that should be there you will have problems.
Working On:Bootloader, RWFS Image Program
Leviathan: http://leviathanv.googlecode.com
Kernel:Working on Design Doc
User avatar
lukem95
Member
Member
Posts: 536
Joined: Fri Aug 03, 2007 6:03 am
Location: Cambridge, UK

Post by lukem95 »

I'd load at the 1 meg mark, this is what GRUB does, and it works well
~ Lukem95 [ Cake ]
Release: 0.08b
Image
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

Post by suthers »

I have changed my jmp to:

Code: Select all

jmp 0x08:0x7e00
But I still get a "stack fault in kernel mode".
I made sure that the code GDT is the second GDT so that 0x08 points to the right GDT.
Any ideas what im doing wrong?
Thanks in advance,

Jules
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

Have you set up a stack? Care to post your code?
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

Post by suthers »

Ok, here is my code:

Code: Select all

[BITS 16]       

[ORG 0x7C00]    
start:
	mov [drive_id], dl
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov ax, 0x1D0
	mov ss, ax
	mov sp, 0x200
	sti
	mov si, init_message
	call PutStr
	call enable_A20
	call read
        cli                                                    

        lgdt [gdt_desc]         

        mov eax, cr0            
        or eax, 1               
        mov cr0, eax            
        jmp 0x08:.32_bit     


[BITS 32]     
                  
	.32_bit   
		mov eax, 10h
		mov ds, eax 
		mov es, eax
		mov fs, eax
		mov gs, eax            
        	mov ss, eax  
		mov dl, 0x04
		mov ecx, 0B81E0h
		mov esi, enabled_32
		call PutStr_32
		jmp 0x08:0x7e00
		.hang
			jmp .hang

PutStr_32:			
	.next_char	
 	lodsb		
 	or al,al			
 	jz .end		
 	mov byte [ds:ecx], al
	inc ecx
	mov byte [ds:ecx], dl
	inc ecx	 
 	jmp .next_char	
	.end
 	ret		

[BITS 16]

enable_A20:
	cli
	call waitkeyclear
	mov al, 0xd1
	out 0x64, al
	call waitkeyclear
	mov al, 0xdf
	out 0x60, al
	call waitkeyclear
	mov cx, 0x10
	.waisttime
	nop
	nop
	xor ax, ax
	loop .waisttime
	mov al, 0xd0
	out 0x64, al
	call waitkeyfull
	in al, 0x60
	test al, 2
	jnz .A20_on
	mov al, 'A'
	call halt
	.A20_on
	sti
	mov si, A20_success
	call PutStr
	sti
	ret


	waitkeyclear:
	xor al, al
	in al, 0x64
	test al, 2
	jnz waitkeyclear
	ret

	waitkeyfull:
	xor cx, cx
	in al, 0x64
	test al, 1
	jz waitkeyfull
	ret



	halt:
	sti
	mov si, A20_fail
	call PutStr
	hlt

PutStr:		
 	mov ah,0x0E	
 	mov bh,0x00	
 	mov bl,0x07	
	.nextchar	
 	lodsb		
 	or al,al			
 	jz .return			
 	int 0x10	 
 	jmp .nextchar	
	.return		
 	ret		

read:
	sti
	xor ax, ax
	mov di, 5
	.track1
	mov al, 1
	mov dh, 0
	mov dl, [drive_id]
	mov ch, 0
	mov cl, 2
	mov bx, 0x7e00
	mov es, bx
	mov bx, 0x0000
	int 0x13
	dec di
	jz .err
	jc .track1
	jmp .success
	.err
	mov si, Read_fail
	call PutStr
	jmp .end
	.success
	mov si, Read_success
	call PutStr
	.end
	mov dx,0x3F2                  
	mov al,0x0C                   
	out dx,al 
	ret

gdt:                    

gdt_null:      
        dd 0
        dd 0

gdt_code:     
        dw 0FFFFh
        dw 0
        db 0
        db 10011010b
        db 11001111b
        db 0

gdt_data: 
        dw 0FFFFh
        dw 0
        db 0
        db 10010010b
        db 11001111b
        db 0

gdt_end:                



gdt_desc:                       
        dw gdt_end - gdt - 1    
        dd gdt                  

enabled_32 db '32bit mode enabled', 0
drive_id dw ''
A20_success db 'A20 Enabled', 13, 10, 0
A20_fail db 'A20 Enabling failed', 13, 10, 0
Read_success db 'Floppy read successfully', 13, 10, 0
Read_fail db 'Floppy read failure', 13, 10, 0
init_message db 'Welcome to SOS V 0.0.1', 13, 10, 0
times 510-($-$$) db 0           
dw 0AA55h                
Any ideas what's wrong with it?
And yes I have set up a stack...
Thanks in advance,

Jules

P.S. Please don't yell at me for any stupid mistakes i've made... :oops:
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
suthers wrote:Ok, here is my code:
:)

Code: Select all

[BITS 16]       

[ORG 0x7C00]
    jmp start             ;Some Compaq machines won't boot if first instruction isn't a JMP

;Should put a dummy BPB (BIOS Paramater Block) here so that DOS/Windows can format the disk
;later (DOS/Windows tends to wet it's pants otherwise)

start:
;   mov [drive_id], dl     ** DS not set yet, so this could write anywhere **
    mov ax, cs
    mov ds, ax
    mov [drive_id], dl    ;** Shifted from above **
    mov es, ax
;   mov fs, ax            ;Segment register unused so no need to initialize
    mov ax, 0x1D0
    cli                   ;Possibly unnecessary, but a good habit (in case IRQ occurs after SS set but before SP set)
    mov ss, ax
    mov sp, 0x200         ;ss:sp = 0x01D0:0x0200 = 0x00002000
    sti
    mov si, init_message
    call PutStr
    call enable_A20
    call read
        cli

        lgdt [gdt_desc]

        mov eax, cr0
        or eax, 1
        mov cr0, eax
        jmp 0x08:.32_bit


[BITS 32]

    .32_bit
        mov eax, 10h
        mov ds, eax
        mov es, eax
        mov fs, eax
        mov gs, eax
        mov ss, eax

;OK, at this point, what does "SS:ESP" contain? The highest 16-bits of ESP
;aren't set to anything and could contain trash. SS_base = 0x00000000 so if
;ESP isn't trash it'd point to 0x00000000+0x00000200 or 0x00000200 (but
;SS:ESP could point to 0x12340200 for all you know).

        mov dl, 0x04
;        mov ecx, 0B81E0h               Assemblers are good - try:
        mov ecx,0B8000 + 6 * (40 * 2)  ;So you can figure out where the magic number came from later
        mov esi, enabled_32
        call PutStr_32
        jmp 0x08:0x7e00
        .hang
            jmp .hang

PutStr_32:
     cld             ;Should set direction *somewhere* before using string instructions
  .next_char
     lodsb
     or al,al
     jz .end
     mov byte [ds:ecx], al    ;Try using "lodsb" with "stosw" (with ah = attribute)
     inc ecx
     mov byte [ds:ecx], dl
     inc ecx
     jmp .next_char
  .end
     ret

[BITS 16]

enable_A20:

;Unfortunately, different motherboards use different methods to enable the
;A20 gate. Try BIOS function first ("mov ax,0x2401; int 0x15"). Also, consider
;testing if A20 actually is enabled correctly instead of assuming it is, by
;testing if the value at 0x0000:0x0000 (or 0x00000000) remains the same as the
;value at 0xFFFF:0x0010 (or 0x00100000).

    cli
    call waitkeyclear
    mov al, 0xd1
    out 0x64, al
    call waitkeyclear
    mov al, 0xdf
    out 0x60, al
    call waitkeyclear
    mov cx, 0x10
    .waisttime             ;Hehe, you mean "waste" not "waist"
    nop
    nop
    xor ax, ax
    loop .waisttime
    mov al, 0xd0
    out 0x64, al
    call waitkeyfull
    in al, 0x60
    test al, 2
    jnz .A20_on          ;Why not do a "jz halt" instead?
;   mov al, 'A'           ** unused **
    call halt            ;WTF - see comments below
    .A20_on
    sti
    mov si, A20_success
    call PutStr
    sti
    ret


    waitkeyclear:
    xor al, al
    in al, 0x64
    test al, 2
    jnz waitkeyclear
    ret

    waitkeyfull:
    xor cx, cx
    in al, 0x64
    test al, 1
    jz waitkeyfull
    ret


;OK, what is this "halt" code meant to do? It looks like it prints a string, then
;waits until an IRQ occurs (could be anywhere from 0 ms to 55 ms), then falls through
;to the "PutStr" routine which prints the string again (starting from the byte after
;the first string's terminator.

    halt:
    sti
    mov si, A20_fail
    call PutStr
.die:
    hlt
    jmp .die        ;I'm guessing you missed this!

PutStr:    
     cld             ;Should set direction *somewhere* before using string instructions
     mov ah,0x0E
     mov bh,0x00

     mov bl,0x07
    .nextchar
     lodsb
     or al,al
     jz .return
     int 0x10
     jmp .nextchar
    .return
     ret

read:
    sti
    xor ax, ax
    mov di, 5
    .track1
    mov al, 1
    mov dh, 0
    mov dl, [drive_id]
    mov ch, 0
    mov cl, 2
    mov bx, 0x7e00
    mov es, bx
    mov bx, 0x0000
    int 0x13
    dec di
;   jz .err             Should see if it worked before deciding it didn't
;   jc .track1
;   jmp .success
    jnc .success
    dec di
    jnz .track1

;WTF? If it didn't load correctly you display a different string and then
;continue as if it has loaded correctly???

    .err
    mov si, Read_fail
    call PutStr
    jmp .end          ;Should probably lock up here instead (note: with interrupt enabled the BIOS will turn floppy motor off).

    .success
    mov si, Read_success
    call PutStr
    .end
    mov dx,0x3F2
    mov al,0x0C
    out dx,al
    ret


        align 4                   ;Align your GDT!
gdt:

gdt_null:
;       dd 0                      ;These values are unused by the CPU, so let's use them!
;       dd 0

        dw 0                      ;First 2 bytes of (unused) NULL descriptor
gdt_desc:                         ;From below
        dw gdt_end - gdt - 1      ;GDT limit (also part of NULL descriptor)
        dd gdt                    ;GDT base address (also part of NULL descriptor)


;I should charge you $20 for adding the comments below... ;-)

gdt_code:
        dw 0FFFFh                 ;Limit (low word) = 0xFFFF

        dw 0                      ;Base (low word) = 0x0000
        db 0                      ;Base (middle byte) = 0x00
        db 10011010b              ;Present, DPL=0, non-system, type = "code execute/read"
        db 11001111b              ;4KB limit granularity, 32-bit default size, limit high nibble = 0xF
        db 0                      ;Base (high byte) = 0x00

gdt_data:
        dw 0FFFFh                 ;Limit (low word) = 0xFFFF
        dw 0                      ;Base (low word) = 0x0000
        db 0                      ;Base (middle byte) = 0x00
        db 10010010b              ;Present, DPL=0, non-system, type = "data read/write"
        db 11001111b              ;4KB limit granularity, 32-bit default size, limit high nibble = 0xF
        db 0                      ;Base (high byte) = 0x00

gdt_end:



;gdt_desc:                         ;Shifted above
;        dw gdt_end - gdt - 1
;        dd gdt

enabled_32 db '32bit mode enabled', 0
drive_id dw ''
A20_success db 'A20 Enabled', 13, 10, 0
A20_fail db 'A20 Enabling failed', 13, 10, 0
Read_success db 'Floppy read successfully', 13, 10, 0
Read_fail db 'Floppy read failure', 13, 10, 0
init_message db 'Welcome to SOS V 0.0.1', 13, 10, 0
times 510-($-$$) db 0
dw 0AA55h
suthers wrote:Any ideas what's wrong with it?
Honestly, no - I can't be sure that any of the problems I noticed would have caused a "stack fault in kernel mode".

To be more honest, IIRC the error messages in VMware are fairly crappy, so "stack fault in kernel mode" could mean anything (not even sure if it's general protection fault or not, or which instruction caused the problem). Try running this through Bochs to get real debugging information so you can find out what's wrong! ;)
suthers wrote:P.S. Please don't yell at me for any stupid mistakes i've made...
I'll try not to mention any of the design flaws (like what's going to happen when the boot code becomes larger than 512 bytes, or the kernel becomes larger than about 600 KB), or the severe lack of comments... :D


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

I tried your code on Boch's but I never got a stack fault in kernel mode,
it just prints the welcome message and then reboots,so I made a few changes,and it's working now,so here you are...

Code: Select all

[BITS 16]        

[ORG 0x7C00]
jmp start

bpbOEM			db "My OS   "
bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	DB 2
bpbRootEntries: 	DW 224
bpbTotalSectors: 	DW 2880
bpbMedia: 		DB 0xf0  ;; 0xF1
bpbSectorsPerFAT: 	DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors: 	DD 0
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
bsUnused: 		DB 0
bsExtBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "
    
start: 
   mov [drive_id], dl 
   mov ax, cs 
   mov ds, ax 
   mov es, ax 
   mov fs, ax 
   mov ax, 0x1D0 
   mov ss, ax 
   mov sp, 0x200 
   sti 
   mov si, init_message 
   call PutStr 
   call enable_A20 
   call read 
        cli                                                    

        lgdt [gdt_desc]          

        mov eax, cr0            
        or eax, 1                
        mov cr0, eax            
        jmp 0x08:.32_bit      


[BITS 32]      
                  
   .32_bit    
       sti
	mov	ax, 0x10		; set data segments to data selector (0x10)
	mov	ds, ax
	mov	ss, ax
	mov	es, ax
	mov	esp, 90000h		; stack begins from 90000h
	
      mov dl, 0x04 
      mov ecx, 0B81E0h 
      mov esi, enabled_32 
      call PutStr_32 
     ; jmp 0x08:0x7e00 
      cli
      hlt

PutStr_32:          
   .next_char    
    lodsb       
    or al,al          
    jz .end       
    mov byte [ds:ecx], al 
   inc ecx 
   mov byte [ds:ecx], dl 
   inc ecx    
    jmp .next_char    
   .end 
    ret       

[BITS 16] 

enable_A20: 
   cli 
   call waitkeyclear 
   mov al, 0xd1 
   out 0x64, al 
   call waitkeyclear 
   mov al, 0xdf 
   out 0x60, al 
   call waitkeyclear 
   mov cx, 0x10 
   .waisttime 
   nop 
   nop 
   xor ax, ax 
   loop .waisttime 
   mov al, 0xd0 
   out 0x64, al 
   call waitkeyfull 
   in al, 0x60 
   test al, 2 
   jnz .A20_on 
   mov al, 'A' 
   call halt 
   .A20_on 
   sti 
   mov si, A20_success 
   call PutStr 
   sti 
   ret 


   waitkeyclear: 
   xor al, al 
   in al, 0x64 
   test al, 2 
   jnz waitkeyclear 
   ret 

   waitkeyfull: 
   xor cx, cx 
   in al, 0x64 
   test al, 1 
   jz waitkeyfull 
   ret 



   halt: 
   sti 
   mov si, A20_fail 
   call PutStr 
   hlt 

PutStr:       
    mov ah,0x0E    
    mov bh,0x00    
    mov bl,0x07    
   .nextchar    
    lodsb       
    or al,al          
    jz .return          
    int 0x10    
    jmp .nextchar    
   .return       
    ret       

read: 
   sti 
   xor ax, ax 
   mov di, 5 
   .track1 
   mov al, 1 
   mov dh, 0 
   mov dl, [drive_id] 
   mov ch, 0 
   mov cl, 2 
   mov bx, 0x7e00 
   mov es, bx 
   mov bx, 0x0000 
   int 0x13 
   dec di 
   jz .err 
   jc .track1 
   jmp .success 
   .err 
   mov si, Read_fail 
   call PutStr 
   jmp .end 
   .success 
   mov si, Read_success 
   call PutStr 
   .end 
   mov dx,0x3F2                  
   mov al,0x0C                    
   out dx,al 
   ret 

gdt:                    

gdt_null:      
        dd 0 
        dd 0 

gdt_code:      
        dw 0FFFFh 
        dw 0 
        db 0 
        db 10011010b 
        db 11001111b 
        db 0 

gdt_data: 
        dw 0FFFFh 
        dw 0 
        db 0 
        db 10010010b 
        db 11001111b 
        db 0 

gdt_end:                



gdt_desc:                        
        dw gdt_end - gdt - 1    
        dd gdt                  

enabled_32 db '32bit mode enabled', 0 
drive_id dw '' 
A20_success db 'A20 Enabled', 13, 10, 0 
A20_fail db 'A20 Enabling failed', 13, 10, 0 
Read_success db 'Floppy read successfully', 13, 10, 0 
Read_fail db 'Floppy read failure', 13, 10, 0 
init_message db 'Welcome to SOS V 0.0.1', 13, 10, 0 
times 510-($-$$) db 0            
dw 0xAA55   
Pleasse note I never tested it on real pc just with Boch's.
The man who follows the crowd will usually get no further than the crowd.
The man who walks alone is likely to find himself in places
no one has ever been before.
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

Post by suthers »

Thanks for checking my code.
Still getting the error though, probably has something to do with how i'm linking it or how the kernel is written...
My kernel:

Code: Select all

char *video_address = (char*)0xB8320;
char attributes = 0x04;
void print(char *text);
void sys_hlt();

void kernel_main()
{
  print("Kernel started");
  sys_hlt();
  while(1){ asm volatile ("nop"); }//just incase the hlt doesn't work (happens occasionally don't know why)
  return;
}

void print(char *text)
{
     while(*text !=0)
     {
                      *video_address = *text;
                      *video_address++;
                      *video_address = attributes;
                      *video_address++;
                      *text++;
    }
    return;
}

void sys_hlt()
{
     asm volatile ("cli");
     asm volatile ("hlt");
     return;
}
My kernel starter:

Code: Select all

[BITS 32]
[global main]
[extern _kernel_main]
main:
	mov dl, 0x04
	mov ecx, 0B8280h
	mov esi, kernel_starter_active
	call PutStr_32
	call _kernel_main
	hlt

PutStr_32:			
	.next_char	
 	lodsb		
 	or al,al			
 	jz .end		
 	mov byte [ds:ecx], al
	inc ecx
	mov byte [ds:ecx], dl
	inc ecx	 
 	jmp .next_char	
	.end
 	ret

kernel_starter_active db 'kernel starter active', 0
My linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(main)
Anything wrong with any of these?
Thanks in advance,

Jules
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

Where is the .text section being linked to? And does that correspond to wherever you are loading your kernel to from the bootloader?
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Okay I think this like
might help you to understand the whole pictue.
The man who follows the crowd will usually get no further than the crowd.
The man who walks alone is likely to find himself in places
no one has ever been before.
Post Reply