Page 1 of 1

FASM Bootloader Woes

Posted: Thu Jun 04, 2009 10:34 pm
by xvedejas
Problem:

Bootloader just causes the machine to restart, doesn't really boot or load...

Desired effect:

Load and jump to binary on second sector of the bootdisk, as well as entering 32-bit protected mode.

How to Reproduce:

Compile following code with fasm, run in qemu.

Code: Select all

use16
jmp main
nop

times 59 db 0ffh

nSectors db 1     ; number of sectors to load

main:
    mov ax,0002h    ; set video mode
    int 10h
	mov byte [0xB8000],"1"
	mov byte [0xB8001],07h
@@: mov ax,0 ; reset floppy device
	mov dl,0
	int 13h
	jc @b ; try again
loadKernel: ; Load the kernel to physical addresss 0:1000h
	mov bx,0
    mov es,bx
    mov bx,1000h
    mov ah,2      ; read sector function code
    mov al,1      ; read 1 sector at a time
    mov ch,0      ; read from track 0   
    mov dl,0      ; read from drive 0 (floopy)
    mov dh,0      ; read from head 0
    mov cl,2      ; sector counter - start from the second sector (first sector is bootloader)
@@: int 13h       ; do it!
	jc loadKernel ; try again.
	cmp cl,[2 + nSectors] ; did we load enough?
	je @f                 ; yep, continue
	add bx,200h           ; nope, do more
	inc cl
    jmp @b
@@:	mov byte [0xB8002],"2"
	mov byte [0xB8003],07h
	cli             ; no interrupts beyond this point
	sub ax,ax
	mov ds,ax       ; set ds to zero for gdt
	lgdt [gdt_desc]
	mov eax,cr0
	or al,1
	mov cr0,eax
	use32
	mov byte [ds:0B8004h], '3'
	mov byte [ds:0B8005h], 07h
	jmp 00h:1000h               ; Jump to the kernel

; Gdt
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               
		
times 510-$ db 00h
dw 0aa55h
I've been trying to figure this out for a while and done searches and looked at other's code and stuff but can't figure it out. Oh, and by the way, first post :)

Re: FASM Bootloader Woes

Posted: Thu Jun 04, 2009 10:54 pm
by geppyfx

Code: Select all

org 7c00h  ;before 'jmp main  '
 ...
xor  ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 7000h
  ...
push 0xb800h
pop  es
mov byte [es:0], 'v'
mov byte [es:1], 7

;now add "jmp $" and test if you see the symbol

Code: Select all

loadKernel: ; Load the kernel to physical addresss 0:1000h
   mov bx,0
    mov es,bx
    mov bx,1000h
    mov ah,2      ; read sector function code
    mov al,1      ; read 1 sector at a time
    mov ch,0      ; read from track 0   
    mov dl,0      ; read from drive 0 (floopy)
    mov dh,0      ; read from head 0
    mov cl,2      ; sector counter - start from the second sector (first sector is bootloader)
@@: int 13h       ; do it!
   jc loadKernel ; try again. 
infinite loop this is if int13 always fails

Code: Select all

use32
   mov byte [ds:0B8004h], '3'
   mov byte [ds:0B8005h], 07h   
   jmp 00h:1000h               ; Jump to the kernel  
jmp 00h:1000h refers to gdt_null
use jmp 8:1000h or jmp (gdt_code-gdt):1000h
and why use32 ?

Code: Select all

@@: int 13h       ; do it!
   jc loadKernel ; try again.
   cmp cl,[2 + nSectors] ; did we load enough?
   je @f                 ; yep, continue
   add bx,200h           ; nope, do more
   inc cl
    jmp @b   
int13 might change CL, better use memory variable
after int13 AH has to be 0(if successful) which means you need to set it to 2h again, AL will be changed as well

Code: Select all

@@: mov ax,0 ; reset floppy device
   mov dl,0
   int 13h
   jc @b ; try again
I personally wouldn't do any checking here at all, you check for errors after int13 ah=2

Re: FASM Bootloader Woes

Posted: Thu Jun 04, 2009 11:59 pm
by geppyfx

Code: Select all

nSectors db 1     ; number of sectors to load   

...

 cmp cl,[2 + nSectors] ; did we load enough?
   je @f                 ; yep, continue     
its either nSectors = 1
or

Code: Select all

 mov al, [nSectors]
 add  al, 2
 cmp cl, al; did we load enough?

Re: FASM Bootloader Woes

Posted: Fri Jun 05, 2009 1:42 pm
by geppyfx
Hello again and welcome to both Fasm & osdev communities.

since you added "org 7c00h" your "times 510-$ db 00h" will no longer work
so:

Code: Select all

  org 7c00h
  use16
boot_sector: 
  jmp  main
...
times 510-$+boot_sector db 00h   
dw 0aa55h 
and in the code where you jumping you should have "org 1000h"
maybe like this

Code: Select all

  org 7c00h
  use16
boot_sector: 
  jmp  main
...
times 510-$+boot_sector db 00h   
dw 0aa55h 
;----------second sector starts---------
org 1000h
use32
  ; your code
this can be compiled as a single file and put at the beginning of floppy/usb

Re: FASM Bootloader Woes

Posted: Fri Jun 05, 2009 5:03 pm
by xvedejas
Thanks for your help guys, but no matter what I try the code seems to restart qemu at the long jump...

Re: FASM Bootloader Woes

Posted: Fri Jun 05, 2009 6:06 pm
by mathematician
Where do you reload ds after switching into protected mode? Unless ds contains an index into the gdt (referencing the data segment) any memory references will get you a general protection error. If there is no interrupt handler to service the exception, you are well on your way to a triple fault.

Re: FASM Bootloader Woes

Posted: Fri Jun 05, 2009 6:57 pm
by b.zaar
xvedejas wrote:

Code: Select all

	cli             ; no interrupts beyond this point
	sub ax,ax
	mov ds,ax       ; set ds to zero for gdt
	lgdt [gdt_desc]
	mov eax,cr0
	or al,1
	mov cr0,eax

	use32

	mov byte [ds:0B8004h], '3'
	mov byte [ds:0B8005h], 07h
	jmp 00h:1000h               ; Jump to the kernel

; Gdt
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               
		
times 510-$ db 00h
dw 0aa55h
I haven't checked it but a quick look at this shows me your using 32 bit code before you've jumped to a 32 bit descriptor/segment. The jump should be in 16 bit still.

Re: FASM Bootloader Woes

Posted: Sat Jun 06, 2009 3:09 am
by mathematician

Code: Select all

use32
   mov byte [ds:0B8004h], '3'
   mov byte [ds:0B8005h], 07h
   jmp 00h:1000h               ; Jump to the kernel
Looking again, that jump will load cs with zero, which will also get you a general protection error. Remember, you are in protected mode now, and the jump ought to load cs with a valid index into the gdt (such as 8 ).

Re: FASM Bootloader Woes

Posted: Sat Jun 06, 2009 5:59 am
by mathematician
Try this

Code: Select all

mov eax, cr0
or eax, 1
mov cr0, eax                  ;switch to protected mode

;--------- THIS IS THE VERY FIRST THING YOU SHOULD DO ONCE YOU ARE IN PROTECTED MODE| -------
db 0eah                         ;opcode for a far jump
dw offset label               ;at least that's how masm would do it. fasm might be "dw label"
                                    ;in either case, it is the offset for the far jump
dw 8                              ;code seg descriptor is eight bytes into the gdt (and what the
                                    ;far jump loads into cs)
label:
;---------------------AND THIS IS THE SECOND -------------------------
mov ax, 10h                 ;data seg descriptor is 16 bytes into the gdt
mov ds,ax                    ;load ds with valid seg selector
mov ss,ax                    ;load ss with valid seg selector
mov esp, 65534            ;or wherever you want to put your stack
......---------------------------------------------------------------------------------------------------------------------------------------------
......
......
......
jump to kernel

Re: FASM Bootloader Woes

Posted: Sat Jun 06, 2009 12:45 pm
by geppyfx
i think you didn't look good enough, there should be plenty of simple real -> protected mode sources in fasm or nasm.

Code: Select all

  org 7c00h
boot_sector:   
  use16
  cli
  xor  ax, ax
  mov  ds, ax
  mov  es, ax
  mov  ss, ax
  mov  sp, 7000h
  ;BIOS will put drive # for int13h in DL, save it !!
  mov  [_drive], dl
  sti
  mov  dword [_signature], 0
  mov  ax, 3
  int  10h

  movzx dx, [_drive]  ; DH = Head number (0-15), DL = Drive number
  mov  cx, 2         ; CH = Cylinder number (0-1023), CL = Sector number (1-17)
  mov  ax, 201h      ;load single sector
  mov  bx, 1000h
  int  13h     
  jc  .error
  cmp  dword [_signature], 77bbbb77h
  je  .switch
.error:
  push 0b800h
  pop  es
  mov  word [es:0], 0404h    ;single red diamond
  jmp  $
.switch:
  cli
  mov  eax, cr0
  or   eax, 1
  lgdt [GDT.reg]
  mov  cr0, eax
  jmp   8h:kernel_32bit

_drive db 0
GDT.reg:
  .limit   dw GDT.ends-GDT-1
GDT:
  .addr   dq GDT
;             [  LIMIT   |   BASE  | PDLSTYPE   GD0ALIMT | BASE ]
.code32:   db  0ffh, 0ffh, 0, 0, 0, 10011010b, 11001111b, 00  ; 8h
.data:     db  0ffh, 0ffh, 0, 0, 0, 10010010b, 11001111b, 00  ; 10h
.ends:
times 510-$+boot_sector db 00h   
dw 0aa55h
;----------second sector starts---------

org 1000h         ;if loaded to 1000h

_signature dd 77bbbb77h      ;preplaced signature

use32
kernel_32bit:
  mov  ax, 10h
  mov  ds, ax
  mov  dword [0b8000h+4], 0e040e04h   ;2 yellow diamons displayed
  jmp  $
is it your switch to PM not working or maybe int 13h failed

Re: FASM Bootloader Woes

Posted: Sat Jun 06, 2009 11:34 pm
by kop99
Here is your code...

Code: Select all

   mov eax,cr0
   or al,1
   mov cr0,eax
   use32
   mov byte [ds:0B8004h], '3'
   mov byte [ds:0B8005h], 07h
   jmp 00h:1000h
Change upper code by following and retry...

Code: Select all

   mov eax,cr0
   or al,1
   mov cr0,eax

   jmp 0x08:code_32
[bits 32]
   code_32:
   mov	ax, 0x10
   mov	ds, ax
   mov	ss, ax
   mov	gs, ax

   mov byte [ds:0B8004h], '3'
   mov byte [ds:0B8005h], 07h
   jmp 08h:1000h