Page 1 of 2

trouble bootloading

Posted: Wed Feb 01, 2012 8:55 pm
by blazinghell
I created my own bootloader via a tutorial and it is supposed to print hello world. It works perfect in qemu, yet does not work when actualy trying to boot. Instead it skips it to my windows installation when selecting to boot directly from the drive. Any ideas as to what the problem could be?

Re: trouble bootloading

Posted: Wed Feb 01, 2012 9:07 pm
by bubach
Are you sure that it's trying to boot from the right media? In that case can we see the code? Did you make sure to include the boot signature at the end of your bootsector? If not, that might be why. Your BIOS might have better error checking to see that it's indeed bootable.

Re: trouble bootloading

Posted: Wed Feb 01, 2012 10:50 pm
by blazinghell
Yes I did check to make sure that the right drive was selected in the boot menu(tried both just in case)

Here is the code that I used:

Code: Select all

[BITS 16]      ; 16 bit code generation
[ORG 0x7C00]   ; Origin location

; Main program
main:		; Label for the start of the main program

 mov ax,0x0000	; Setup the Data Segment register
		; Location of data is DS:Offset
 mov ds,ax	; This can not be loaded directly it has to be in two steps.
		; 'mov ds, 0x0000' will NOT work due to limitations on the CPU

 mov si, HelloWorld	; Load the string into position for the procedure.
 call PutStr	; Call/start the procedure

jmp $		; Never ending loop

; Procedures
PutStr:		; Procedure label/start
 ; Set up the registers for the interrupt call
 mov ah,0x0E	; The function to display a chacter (teletype)
 mov bh,0x00	; Page number
 mov bl,0x07	; Normal text attribute

.nextchar	; Internal label (needed to loop round for the next character)
 lodsb		; I think of this as LOaD String Block 
		; (Not sure if thats the real meaning though)
		; Loads [SI] into AL and increases SI by one
 ; Check for end of string '0' 
 or al,al	; Sets the zero flag if al = 0 
		; (OR outputs 0's where there is a zero bit in the register)
 jz .return	; If the zero flag has been set go to the end of the procedure.
		; Zero flag gets set when an instruction returns 0 as the answer.
 int 0x10	; Run the BIOS video interrupt 
 jmp .nextchar	; Loop back round tothe top
.return		; Label at the end to jump to when complete
 ret		; Return to main program

; Data

HelloWorld db 'Hello World',13,10,0

; End Matter
times 510-($-$$) db 0	; Fill the rest with zeros
dw 0xAA55		; Boot loader signature

It was compiled using nasm with

Code: Select all

nasm.exe boot.txt -f bin -o boot
I then wrote it to the drive using RMPREPUSB.

Also I have verified that it wrote by using the Drive->File function of RMPREPUSB and it showed the exact same binary as was compiled.

Any help for what I am doing wrong would be greatly apprecieated.

I am new to OS Development and figured that the best place to start would be the beginning.

Re: trouble bootloading

Posted: Wed Feb 01, 2012 11:31 pm
by CelestialMechanic
I don't think the ax and bx registers are preserved by INT 10H.

I had a look at one of my boot sectors and here's my bprint function. Notice that I reload BX and AH each time through the loop.

Code: Select all

bprint	proc near
	mov	bx, 0007H
	lodsb
	or	al, al
	je	bpout
	mov	ah, 0eH
	int	10H
	jmp	bprint
bpout:
	ret
bprint	endp
I hope this helps.

Re: trouble bootloading

Posted: Thu Feb 02, 2012 12:22 am
by blazinghell
If it simply did not preserve the values then it would at least print out one character correct? After trying it on a different computer it just hangs with a blinking line in the top left, not printing out anything.

Also I am running on a quad core, could that have something to do with it?

Re: trouble bootloading

Posted: Thu Feb 02, 2012 6:26 am
by Combuster
blazinghell wrote:I then wrote it to the drive using RMPREPUSB.
Which is a tool originally written to make windows bootable from USB (didn't that just happen?)

Get a decent tool that can write your bootsector to the physical first sector instead of using someone else's bootloader. A windows version of dd that supports usb drives would be the right way to go.

Re: trouble bootloading

Posted: Thu Feb 02, 2012 7:03 am
by turdus
You forget to set up a stack. Typical beginner's mistake.
You use lodsb instruction without clearing direction flag. Could be set on real machine.
Every byte counts, so do not use "mov ax, 0", use "xor ax, ax" instead.
Use correct tool (like dd or rawrite) as Combuster suggested.

Re: trouble bootloading

Posted: Thu Feb 02, 2012 12:24 pm
by steve6375
Hi
RMPrepUSB should work no problem (I wrote it) and is safer than dd in that it will only select a USB drive by default. The latest Beta version also has a disk editor which allows you to see and edit the sector contents (or use Disk Info button in RMPrepUSB).
If you want to write some boot code, then take a look at the TESTMBR folder which is in RMPrepUSB installation folder (press F3). It includes the source code assembler file TESTMBR.ASM which you may find informative.

In your code you are loading DS with 0 but you have the ORG set to 7c00. It might be safer to load DS with CS (via AX). Not all BIOSes load code at 7c00, many use 7c0:0 and some others use a different address. I use offset addresses for this reason. Look at the value used for the offset in the instruction mov si,'hello world' - is it correct or is it 7cxx?

For a BIOS to run the boot code, the last two bytes should be 1FE=55 1FF=AA.

P.S. lodsb is load string byte, guess what lodsw is??? ;=)

Re: trouble bootloading

Posted: Thu Feb 02, 2012 2:20 pm
by blazinghell
I am guessing that lodsw is loading a string word? BTW props for the awesome app, it works wonderfully on vista, something that most others fail to do. Also it works when using external hard drives connected via USB XD.


Also thanks for your input, although I am rather limited on time right now I will be sure to try out your suggestions later today.

@combuster no it did not boot windows from the usb... it booted it from my primary hdd, completely skipping over the bootloader probably because I screwed it up...

Also does anyone know why this runs in an emulator but not on the real machine? At this point I just want to see something happen.

Re: trouble bootloading

Posted: Thu Feb 02, 2012 3:48 pm
by Unkn0wn1
Just out of curiosity,what kind of media are you running it as in QEMU? if you have a floppy drive, i might suggest testing it on there

Re: trouble bootloading

Posted: Thu Feb 02, 2012 4:17 pm
by blazinghell
I am booting it as a hard disk in qemu through the rmprepUSB test buton


After trying the real mode assembly tutorial, the one where the OS is put into the boot sector I can verify that rmprepusb is working just fine. As such the problem is not the tools but the code itself. I guess it is time to hit the assebly books and get to work. Thanks again for all your help everyone, and let me know if you find out what is broken, as I am still largely a newb in assembly. . . Goo c/c++

Re: trouble bootloading

Posted: Thu Feb 02, 2012 5:34 pm
by DavidCooper
blazinghell wrote:As such the problem is not the tools but the code itself. I guess it is time to hit the assebly books and get to work.
You say it gets bypassed on one machine which just ignores it and boots Windows, while another machine tries to boot it and just blinks a cursor at you. That suggests that one of the machines has loaded and started to run your boot sector, but you go straight into some code using the BIOS to print to the screen which opens up loads of opportunities for bugs which I can't be bothered hunting down. Why don't you just start by putting b800 into es (via ax), then put 0 in di, then put 65 in al (decimal value for the letter A) and 12 (colour value for red) in ah and send them to the top left corner of the screen with stosw, and then go into a long or infinite loop (best to go for an infinite one as a simple long loop will be so quick on a modern machine that the red A could still be overwritten with nothing before you get a chance to see it). If you do that you'll find out for certain if any of your code is running.

The reason one machine is working and the other not may be something to do with where you've stored your boot sector on the USB drive. Is it at the start of a partition, or have you overwritten the MBR with it? If the latter, it will pretend to be a floppy disk, whereas the former will pretend to be a hard disk. From what I've read, some machines can boot using either arrangement, while others can only handle one of them (though you may be able to change a setting in the BIOS to switch it). More than that I do not know and I cannot be sure that even that is correct, but it would fit with what you're finding.

Edit: I've had a quick look through it for bugs and can't see anything obvious. I don't have a proper copy of the BIOS calls for printing chars - no one serious uses them these days.
blazinghell wrote: PutStr: ; Procedure label/start
; Set up the registers for the interrupt call
mov ah,0x0E ; The function to display a chacter (teletype)
mov bh,0x00 ; Page number
mov bl,0x07 ; Normal text attribute
Assuming those are right, there's no guarantee that they're preserved after each BIOS call - you should push them all and pop them afterwards to be on the safe side. I wouldn't be surprised if a modern BIOS has a major bug in this function either as there can't be many programs that would ever put it to the test.
lodsb ; I think of this as LOaD String Block
; (Not sure if thats the real meaning though)
I suspect the b stands for byte, and the w in lodsw stands for word.

Re: trouble bootloading

Posted: Thu Feb 02, 2012 8:04 pm
by blazinghell
David you are a genius!!!

i was overwriting the mbr, so I switched to writing it to the primary partition and it booted up like a dream. Though this is the assembly os that does not use a bootloader, I have pretty much abandoned the above code and will modify the assembly os to suit my needs.

Thank you so much for your help everyone.

Re: trouble bootloading

Posted: Tue Feb 07, 2012 11:57 am
by Ariethenor
I am trying to build a simple boot loader. I have this code working on bochs on two separate computers, and it boots via usb on a Dell inspiron 1750 (intel pentium inside), however on my box with ASUS M3N-HT deluxe, with AMD Penom x64 Quad, It does not boot via USB, just a flashy cursor in the corner. I am wondering if I am having similar issues as above, or if my bootloader is going completely in the wrong direction.

The following code works on all applications except my AMD via usb.

wondering if it has something to do with intel vs. AMD syntax??? I was under the impression they should be identical... Any help is greatly appreciated.

Code: Select all

;==============================================================================
;  test assembled with: cd %COSPATH%/fasm/ && ./fasm %PATH%/CruiseOS/kernel_sa.asm %PATH%/CruiseOS/kernel.bin
;	 ".bin" is for flashing	to bochs hdd image
;  release assembled with: cd %COSPATH%/fasm/ && ./fasm %PATH%/CruiseOS/kernel.asm %PATH%/CruiseOS/kernel.img 
;	".img" is for flashing onto usb
;  Kernel is flashed to usb using ImageWriter for Ubuntu
;  Kernel is flashed to a 4gb bochs hdd using a cpp program I created, let me know if you need a copy of the 
;	program source.
;
;File Name: kernel_sa.asm
;Revision: New
;Date Created: January 15th, 2012 
;Date Last Modified: February 7th 2012
;Version: 0.0.0b.0
;Supported OS: CruiseOS
;Author: Timothy Giddens
;
;Assembled with: FASM
;	ver: 1.69.35
;Overview:
;	This is the kernel modual of CruiseOS with minimum procedures directly included, so 
;	that this is stand alone. This file is intended for use when asking for help.


format binary			;FASM outputs the file in machine code directly as writen below
				;This is to facilitate flashing directly to USB

use16				;Use x86 16-bit opcodes

label BOOT_SEC_START at 0x07C0 	;BIOS loads boot sec into segment:offset 0x07C0:0000
	
  mov ax, BOOT_SEC_START	;Initialize segments for boot loader
  mov ds, ax
  mov es, ax

LBA_CHECK:			;This checks the BIOS for LBA compatability
  mov ah, 0x41			;BIOS LBA Check operation
  mov bx, 0x55AA
  mov dl, 0x80			;HDD 1 (susspect this is why not booting on AMD box)
  int 0x13
; jc error 			;Sets carry on error. Some sort of exeption handler will go here eventually

DAP:				;(Disk Address Packet)This data structure is used for LBA reads
  db 0x10			;Always 0x10 (16) (structure size)
  db 0x00			;Always 0x00
  dw 0x0003			;Number of LBA's to read (512 bytes per LBA) (max 16 sectors per read) (max 8192 bytes per read)
  dd 0x0000:0x0500		;Segment:offset of memory to read bytes to.
  dq 0x0000000000000001		;LBA # to start read.


LBA_READ:			;This reads data from hdd
  mov si, DAP			;Point to data structure
  mov ah, 0x42			;BIOS LBA read operation
  mov dl, 0x80			;
  int 0x13

  jmp 0x00:0x0500		;Jump to kernel segment
  
  db 510-($-$$) dup 0 		; boot sector must be 510 bytes plus 2 bytes at BOOT_SEC_END
  
BOOT_SEC_END:
  db 0x55
  db 0xAA

org 0x0500			;Set everything to address from zero in kernel segment
KERNEL_START16:			;Start of 16-bit mode

;***********************Macros************************
macro ClrScr
{
  call clr_scr
}

macro WriteString STRING*		;STRING structure, or reg pointing to
					;string
{
  pushad
  mov si, STRING
  call write_string
  popad
}

macro GetInput BUFFER*		;BUFFER structure
{
   mov di, BUFFER
   mov dh, [#BUFFER#.size]
    call get_input
}

macro strcmp string1*,string2*
{
  pushad
  mov si, string1
  mov di, string2
  call pStrcmp
  popad
}

struc STRING [string]
;structure creates a null terminated string and a size.
{
  common
  . db string
  db 0
  .size = $ - .
}

struc BUFFER size
;creates a buffer of size.
{
  common
  . db size dup 0
  .size = $ - .
}

lf equ 0x0A
cr equ 0x0D
nl equ lf,cr

;*********************END MACROS***************************


  mov ax, 0x0000  		; set up segments
  mov ds, ax
  mov es, ax
  jmp start

start:
  ClrScr
  WriteString welcome
  jmp mainloop
 
mainloop:
  WriteString prompt
 
  GetInput input
 
  mov si, input
  cmp byte [si], 0  		;If the input line is blank ignore it
  je mainloop       		;
 
  strcmp cmd_hi, input  	; "hi" command
  jc .helloworld
 
  strcmp cmd_help, input  	; "help" command
  jc .help

  strcmp cmd_test, input	; "test" command
  jc .test
 
  WriteString badcommand 
  jmp mainloop  
 
.helloworld:
  WriteString msg_helloworld

  jmp mainloop
 
.help:
  WriteString msg_help
 
  jmp mainloop


;*****************TEST PROGRAM AREA******************
;This is where I am putting code as I test my system

.test:
  
jmp mainloop
;*****************END TEST AREA**********************

;*****************DATA*******************************
 
  welcome STRING 'Welcome to CruiseOS V.0.0.0b.0!',nl
  msg_helloworld STRING 'Hello User!',nl
  badcommand STRING 'Bad command entered.',nl
  prompt STRING '$>'
  cmd_hi STRING 'hi'
  cmd_help STRING 'help'
  cmd_test STRING 'test'
  msg_help STRING 'My OS: Commands: hi, help, test',nl
  input BUFFER 64

KERNEL_END:

;*******************Procedures********************
;These were all pulled out of the include files
;So this can be assembled and tested as is, 
;Thanks for your help!.


clr_scr:
  pusha
  mov cx, 0x0000		;0x'row''column' (upper row)
  mov dx, 0x184F		;0x'row''column' (lower row)
  mov bh, 0x07			;black bkgd, white cursor blink enabled
				;will change this to a var later
  mov ax, 0x0600		;0x'scroll up''num rows' 0=all
  int 0x10			;BIOS interrupt
  
  mov bh, 0x00			;Page number
  mov dx, 0x0000		;0x'row''column'
  mov ah, 0x02			;Set cursor position
  int 0x10			;BIOS interrupt
  popa
ret ;END clr_scr


write_string:
  lodsb        			;Load a byte based on SI
 
  or al, al  			;If result is zero then al is zero
  jz .done   			;and we have reached end of string 
  mov ah, 0x0E			;If al not zero print the character
  int 0x10      		;
 
  jmp write_string		;Try next character
 
  .done:			;Done printing
    ret
;End WriteString

get_input:
   xor cl, cl			;wipe out cl used as a counter
 
  .loop:
    mov ah, 0			;wait for user keypress
    int 0x16   			;users key will be in AL
    cmp al, 0x08
    je .backspace		;Handle backspace event   
    cmp al, 0x0D 
    je .done      		;Handle enter/return event
    cmp al, 0x1B		;
    je .escape			;handle escape event
    sub dh, 1
    cmp cl, dh		 	;Will only read in up to one less buffer size
    je .loop      		;If limit is reached only enter and backspace is read
    mov ah, 0x0E
    int 0x10      		;Print out "Echo" character
    stosb  			;put character in buffer
    inc cl			;Increment character count
    jmp .loop			;Return for more input
 
  .backspace:			;Handle backspace event
    cmp cl, 0			;If this is the beginning of the prompt
    je .loop			;ignore that backspace was pressed
    dec di			;Move back one character in "buffer"
    mov byte [di], 0		;Write a null "delete character"
    dec cl			;decrement character count

    mov ah, 0x0E		;"Echo" backspace
    mov al, 0x08		;"cursor back one space"
    int 10h			;
    mov al, ' '			;black char print
    int 10h			;
    mov al, 0x08		;"cursor back one space"
    int 0x10			;
 
    jmp .loop			;Get more input

  .escape:
    cmp cl, 0
    jg .decpos
    mov byte [di], 0x1B
    jmp .done
  .decpos:
    cmp cl, 0			;If this is the beginning of the prompt
    je .loop			;ignore that backspace was pressed
    dec di			;Move back one character in "buffer"
    mov byte [di], 0		;Write a null "delete character"
    dec cl			;decrement character count

    mov ah, 0x0E		;"Echo" backspace
    mov al, 0x08		;"cursor back one space"
    int 10h			;
    mov al, ' '			;black char print
    int 10h			;
    mov al, 0x08		;"cursor back one space"
    int 10h	
  jmp .escape

  .done:
    mov al, 0			;Add a null terminator to the string
    stosb
 
    mov ah, 0x0E		;Move cursor to new line
    mov al, 0x0D		;Carriage Return
    int 0x10
    mov al, 0x0A		;Line Feed	
    int 0x10
 
  ret
;End get_input


pStrcmp:
  .loop:
    mov al, [si]   		;Grab a byte from SI
    mov bl, [di]   		;Grab a byte from DI
    cmp al, bl     		;Are the two equal?
    jne .notequal  		;If not then exit.
 
    cmp al, 0  			;If both bytes are here they are equal, if they are null then the strings are finished
    je .done   			;yes, we're done.
 
    inc di     			;increment DI
    inc si     			;increment SI
    jmp .loop  			;
 
  .notequal:
    clc  			;Clear the carry flag if strings are not equal
    ret
 
  .done: 	
    stc  			;Set the carry flag if strings are equal
    ret
;End strcmp

macro mPadhddseg
;
;	the intent of this macro is to pad the current address space to a 512
;	byte boundry for direct flashing of the kernel so that it boots
;	properly.
;
{
  if $-$$ = 0
  else
    pad equ (((($-$$)/512)+1)*512)-($-$$)
    if pad = 0
    else
      db pad dup 0
    end if
  end if
}
  
mPadhddseg

Re: trouble bootloading

Posted: Tue Feb 07, 2012 1:07 pm
by turdus
Ariethenor wrote:I am trying to build a simple boot loader. I have this code working on bochs on two separate computers, and it boots via usb on a Dell inspiron 1750 (intel pentium inside), however on my box with ASUS M3N-HT deluxe, with AMD Penom x64 Quad, It does not boot via USB, just a flashy cursor in the corner. I am wondering if I am having similar issues as above, or if my bootloader is going completely in the wrong direction.

The following code works on all applications except my AMD via usb.

wondering if it has something to do with intel vs. AMD syntax??? I was under the impression they should be identical... Any help is greatly appreciated.
Intel vs. AMD syntax? Wtf?

It's full of bugs. You do not set up a stack, clear direction flag, disable interrupts, etc. etc. etc.

Code: Select all

; jc error 			;Sets carry on error. Some sort of exeption handler will go here eventually

DAP:				;(Disk Address Packet)This data structure is used for LBA reads
  db 0x10			;Always 0x10 (16) (structure size)
  db 0x00			;Always 0x00
  dw 0x0003			;Number of LBA's to read (512 bytes per LBA) (max 16 sectors per read) (max 8192 bytes per read)
  dd 0x0000:0x0500		;Segment:offset of memory to read bytes to.
  dq 0x0000000000000001		;LBA # to start read.
Works with error check disabled? And executing lba packet? It's really hard to believe it works at all...

Edit: oh, and you do not take into count partitions. GPT impossible by your design, MBR partitions missing. USB drives must have at least one partition.