[SOLVED][Two-Stage-BootLoader] Can't load the second stage

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
AlpacaSolitario
Posts: 2
Joined: Sun Apr 15, 2018 3:28 pm

[SOLVED][Two-Stage-BootLoader] Can't load the second stage

Post by AlpacaSolitario »

Hi to everyone,
i'm trying to write a two stage bootloader, but I have some problem with the loading of the second stage in memory.
This is the code of the first stage of bootloader (the labels LABEL_RESET_FLOPPY and LABEL_READ_STAGE_UNO are the ones used to read from the floppy drive):

Code: Select all

	.org 0x0
	.text
	.code16
	.globl _start

_start:	
LABEL_INIT:	cli
		jmp LABEL_STAGE_ZERO

LABEL_STAGE_ZERO:
        #Set %ds %es %ss %si to 0
	xor %ax,%ax		
	mov %ax,%ds		
	mov %ax,%es
	mov %ax,%ss
	mov %ax,%si
       
        #Set stackpoint to 0x7c00
	movw $0x7c00,%sp		
	sti
#Here the floppy drive is resetted
LABEL_RESET_FLOPPY:
	
	mov $0x00,%ah
	mov $0x00,%dl
	int $0x13
	jc LABEL_RESET_FLOPPY
	
	#Set es to 0x50 and bx to 0x0
       #The second stage will be loaded at 0x500
	mov $0x50,%ax
	mov %ax,%es
	xor %bx,%bx
	
LABEL_READ_STAGE_UNO:
	
	
	#Read the second sectory of the floppy disc
	mov $0x02,%ah
	mov $1,%al    #number of sector to read
	mov $2,%ch   #cylinder number
	mov $2,%cl    #sector number
	mov $0,%dh  #head number
	mov $0,%dl
	int $0x13

	#If there is an error try again
	jc LABEL_READ_STAGE_UNO
	

LABEL_NEXT_STAGE:
        #Jump to the second stage
	ljmp $0x50,$0x0
I checked the %ah register after the read of the second sector and it was set to 0x0 which should be a successful completion. But when I try to jump to the loaded stage the cursor hangs.

Thanks to everyone.
Last edited by AlpacaSolitario on Mon Apr 23, 2018 5:08 am, edited 1 time in total.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: [Two-Stage-BootLoader] Can't load the second stage

Post by BenLunt »

AlpacaSolitario wrote:Hi to everyone,
i'm trying to write a two stage bootloader, but I have some problem with the loading of the second stage in memory.
This is the code of the first stage of bootloader (the labels LABEL_RESET_FLOPPY and LABEL_READ_STAGE_UNO are the ones used to read from the floppy drive):
Your actual error is further below, but I will make comments here as well.

Code: Select all

	.org 0x0
	.text
	.code16
	.globl _start

_start:	
;; this is not needed.  Neither the 'cli' nor the jmp.  First of all, there is no need
;;  to clear interrupts.  If your BIOS (the only thing that can interrupt you at the moment)
;;  doesn't restore the registers correctly, there is no need to continue further.
;; Second, a relative short jump does nothing for the boot code.  In fact, the
;;  only time I ever have seen that it is needed was with a specific BIOS manufacturer
;;  and version.  They would check that the first instruction was indeed a jump.
LABEL_INIT:	cli
		jmp LABEL_STAGE_ZERO

LABEL_STAGE_ZERO:
        #Set %ds %es %ss %si to 0
	xor %ax,%ax		
	mov %ax,%ds		
	mov %ax,%es
	mov %ax,%ss
	mov %ax,%si
       
        #Set stackpoint to 0x7c00
	movw $0x7c00,%sp		
	sti
;; again, no need for the cli/sti.  The processor will not allow an interrupt
;; after the setting of 'ss' between it and the next instruction, usually the
;; setting of 'sp'.

#Here the floppy drive is resetted
LABEL_RESET_FLOPPY:

;; The need for this is debatable. The BIOS has already read your sector to
;;   0x07C00 so the disk system obviously works okay, so no need to reset it
;; However, there really isn't anything wrong with doing so.
	mov $0x00,%ah
	mov $0x00,%dl
	int $0x13
	jc LABEL_RESET_FLOPPY
	
;; This is your error:
;; There is still BIOS stuff at 0x00500.  If you load your second stage to 0x00500,
;;   you have overwritten necessary data that the BIOS needs to use for disk and
;;   other operations.
	#Set es to 0x50 and bx to 0x0
       #The second stage will be loaded at 0x500
	mov $0x50,%ax
	mov %ax,%es
	xor %bx,%bx
	
LABEL_READ_STAGE_UNO:
	#Read the second sectory of the floppy disc
	mov $0x02,%ah
	mov $1,%al    #number of sector to read
	mov $2,%ch   #cylinder number
	mov $2,%cl    #sector number
	mov $0,%dh  #head number
	mov $0,%dl
	int $0x13

	#If there is an error try again
	jc LABEL_READ_STAGE_UNO
	

LABEL_NEXT_STAGE:
        #Jump to the second stage
	ljmp $0x50,$0x0
The best way to find out what is going on is to run it through an emulator with the debugger set. For example, Bochs will let you single step through instructions. It will even let you break at a known instruction offset, say 0x07C00, then single step through the code (skipping the BIOS calls with other break codes).

Ben
- http://www.fysnet.net/osdesign_book_series.htm
MichaelPetch
Member
Member
Posts: 799
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: [Two-Stage-BootLoader] Can't load the second stage

Post by MichaelPetch »

BenLunt wrote: ;; again, no need for the cli/sti. The processor will not allow an interrupt
;; after the setting of 'ss' between it and the next instruction, usually the
;; setting of 'sp'.
Back when I wrote my first bootloader while doing work with Wendin's PCNX back in the 80s I learned it was not uncommon for CLI and STI to wrap even an SS update followed by a change to SP. You are correct in your observation that when you update SS the interrupts are turned off for the duration of the next instruction too. There was a SNAFU with a batch of 8088s that were sold where the interrupts were not turned off as expected when updating SS. Most bootloaders back then didn't take the chance so they were often coded to do an explicit CLI before updating SS:SP. More about that 8088 bug can be found in this PC Magazine article

Regarding the short JMP, agreed some BIOSes would attempt to look for the first instruction being some well known OPCode (XOR, a short JMP etc). What use to be more common was a far jump to the next instruction to set CS to the expected value. If a bootloader ever used something like absolute indirect jumps this would be required. So if you did see a JMP it would likely have looked something like:

Code: Select all

      ljmp $0x0000,$LABEL_STAGE_ZERO

LABEL_STAGE_ZERO:
This of course isn't needed here since nothing in this bootloader code relies on CS actually being zero. Some BIOSes may jump to the bootloader via 0x07c0:0x0000 rather than 0x0000:0x7c00 so in theory this could be an issue in someone else's bootloader depending on how it is coded.
MichaelPetch
Member
Member
Posts: 799
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: [Two-Stage-BootLoader] Can't load the second stage

Post by MichaelPetch »

Your code comments suggest Read the second sectory of the floppy disc is the goal. The second sector on the disk (right after the boot sector) is Cylinder 0, head 0, sector 2 however in your code you have:

Code: Select all

mov $2,%ch   #cylinder number
You sure you want to be using Cylinder 2 rather than cylinder 0?
AlpacaSolitario
Posts: 2
Joined: Sun Apr 15, 2018 3:28 pm

Re: [Two-Stage-BootLoader] Can't load the second stage

Post by AlpacaSolitario »

Ok guys, thank you very much for all your answers. The problem was that I was reading the wrong cylinder (I was reading cylinder 2 instead of cylinder 0 , don't know way I put 2 there...).
Now I am able to load the second boot stage and to run it.
Also thank you for your suggestions about cli,sti and the jmp.
Post Reply