[SOLVED] Bootloader fails on a real pc

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.
Bietje
Member
Member
Posts: 100
Joined: Wed Apr 20, 2011 6:57 am

[SOLVED] Bootloader fails on a real pc

Post by Bietje »

Hello there,

I'm developping a bootloader and everythings goes quit well. I use bochs or kvm to test. Today I tried to boot from a real computer, and that failed. I used an USB harddrive (pendrive) and my first sector gets loaded perfectly the disk reader doesn't show errors either but when i try to far jump it fails.

I can't figure out why it works with bochs or kvm but fails with a real pc..

My first stage:

Code: Select all

[BITS 16]
[ORG 0x7C00]
main: ; entry point
	mov [bootdisk], dl
	mov si, booted
	call println

	call loadimage
	shr ax, 8
	or al, al
	jz .loaded

.bailout:
	mov si, failed
	call println
	xor ax, ax
	int 0x16
	int 0x19
	cli
	jmp $

.loaded:
	mov dl, [bootdisk]
	jmp 0x7C0:0x200
	mov si, failed
	call println
	cli
	jmp $

;
; Image loader
;

%include 'boot/x86/stage1/loadimage.asm'

;
; Print routines
;

%include 'boot/x86/println.asm'

;
; Since flat binary is one big heap of code without sections, is the code below some sort of data section.
;

	bootdisk db 0
	booted db 'GEBL has been loaded by the bios! Executing...', 0x0
	failed db '(0x0) Failed to load the next stage.. ready to reboot. Press any key.', 0x0

times 510 - ($ - $$) db 0
dw 0xAA55
loadimage.asm

Code: Select all

loadimage:
	
.checkextensions:
	mov ah, 0x41	; check ext
	mov dl, [bootdisk]	; HDD0
	mov bx, 0x55AA
	int 0x13
	jc .checkextensions

.extread:
	mov ah,0x42
	mov dl,[bootdisk]
	lea si,[lbar]        
	int 0x13
	jnc .return

.oldway:
	xor ah, ah ; function 0 = reset
	mov dl, [bootdisk]
	int 0x13
	jc .oldway

.oldload:
	mov bx, 0x7C0	; segment
	mov es, bx
	mov bx, 0x200	; offset

	mov ah, 0x2					; function 2
	mov al, 0x1					; read 1 sector
	xor ch, ch					; track
	mov cl, 0x2					; sector to read
	xor dh, dh					; head number
	mov dl, [bootdisk]					; drive number
	int 0x13					; call BIOS - Read the sector

.return:
	ret
;
; LBA register
;
; Loading a sector with this seg:off will place it right after the mbr
;

lbar:
	db 0x10      	; register size
	db 0      	; reserved, must be 0
	dw 0x1      	; sectors to read
	dw 0x200   	; memory offset
	dw 0x7C0   	; memory segment
	dq 0x1		; starting sector (sector to read)
And sector 2 (which will be read)

Code: Select all

main:
	mov [diskid], dl

	call enable_A20
	jnc  .loadstage2
	mov si, a20fail

.bailout:
	call println
	xor ah, ah
	int 0x16
	int 0x19
	cli
	jmp $

.loadstage2:
	mov si, a20ok
	call println
	
	call getmemorymap
	mov si, a20fail
	jc .bailout

	mov ax, word [mmr+4]
	or ax, ax
	jz .bailout		; we are not here to bully our user with al zero-length memory map.

	call dynamicloader
	shr ax, 8
	or al, al
	mov si, nostage2
	jnz .bailout

	jmp 0x7E0:0x400

	jmp .bailout

;
; Dynamic disk reader
;

%include 'boot/x86/stage1/stage1.5/dynamicloader.asm'

;
; Memory map
;

%include 'boot/x86/stage1/stage1.5/getmemorymap.asm'

;
; A20 Gate
;

%include 'boot/x86/stage1/stage1.5/enable_A20.asm'

;
; Print routines
;

%include 'boot/x86/println.asm'
	
	diskid db 0
	a20ok db 'The A20 line has been enabled.', 0x0
	a20fail db '(0x1) The A20 gate couldn`t be opened. Press a key to reboot.', 0x0
	nostage2 db '(0x2) Failed to load the second stage.. Press a key to reboot.', 0x0

times 1024 - ($ - $$) db 0
Does any of you see, why the far jump does what I want in real mode but does not in a real PC. Oh and my linker makes sure the second stage is at 0x7E00

Code: Select all

SECTIONS
{	
	.boot 0x7E00:
	{
		*(.stage1)
		*(.stage2)
		*(.pmode)
	}
	.text :
	{
		*(.text)
	}
	.rodata :
	{
		*(.rodata)
	}
	.data :
	{
		*(.data)
	}
	.bss :
	{
		*(.bss)
	}
	.end ALIGN(2) :
	{
		*(.end)
	}
}
It just hangs there after displaying the first message.. why kvm loads the entire bootloader..

Thanks in advance.
Last edited by Bietje on Tue May 17, 2011 6:28 am, edited 1 time in total.
robos
Member
Member
Posts: 33
Joined: Sun Apr 06, 2008 7:04 pm
Location: Southern California

Re: Bootloader fails on a real pc

Post by robos »

You need to set up a stack and your DS & ES registers. You have no idea now where the stack is, how large it is or where "mov [bootdisk], dl" gets written to
- Rob
Bietje
Member
Member
Posts: 100
Joined: Wed Apr 20, 2011 6:57 am

Re: Bootloader fails on a real pc

Post by Bietje »

I also thought of that.. So should I set my data and es segment registers to 0? And do I have to that in stage 1 ánd stage 1.5 or just in stage 1?

So:

Code: Select all

xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7BFE
mov bp, sp
still doesn't work at all..
Bietje
Member
Member
Posts: 100
Joined: Wed Apr 20, 2011 6:57 am

Re: Bootloader fails on a real pc

Post by Bietje »

So.. I have found the error. I thought my bios recognizes my usb as harddisk so I used 0x80 in dl in the disk reader. Now I have another problem.. what number should I use in dl? 0x0 for a floppy also fails :|
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Bootloader fails on a real pc

Post by Firestryke31 »

Use [bootdisk]. That's the whole reason it exists, isn't it?
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
Bietje
Member
Member
Posts: 100
Joined: Wed Apr 20, 2011 6:57 am

Re: Bootloader fails on a real pc

Post by Bietje »

If I use mov [bootdisk], dl it triple faults (I tested on my main pc and it spams the first bootmessage of stage 1 10000 milion times)..
And if I do not use the disk number supplied by the bios in dl but use a static value like 0x0 for floppy or 0x80 it doesn't load the correct sectors..
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bootloader fails on a real pc

Post by DavidCooper »

Bietje wrote:If I use mov [bootdisk], dl it triple faults (I tested on my main pc and it spams the first bootmessage of stage 1 10000 milion times)..
And if I do not use the disk number supplied by the bios in dl but use a static value like 0x0 for floppy or 0x80 it doesn't load the correct sectors..
Where is that going to in memory? 0? It looks as if it's probably messing up the first of the BIOS's interrupt vectors, and as that one gets triggered 18 times a second you're going to get a crash straight away. You need to set up the segment registers right at the start and pick an address to store the drive number where it isn't going to cause any harm.

Bochs probably doesn't bother to simulate real mode interrupts - it certainly doesn't appear to update the system timer variable in the BDA, so you're probably using memory you shouldn't and getting away with in Bochs by luck.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
CelestialMechanic
Member
Member
Posts: 52
Joined: Mon Oct 11, 2010 11:37 pm
Location: Milwaukee, Wisconsin

Re: Bootloader fails on a real pc

Post by CelestialMechanic »

Bietje wrote:{Snip!}

Code: Select all

xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7BFE
mov bp, sp
still doesn't work at all..
Where did you place this code? It should be after your main: label and before mov [bootdisk],dl.

It might also be a good idea to place a far jump like this first thing after main and before the snippet quoted above just in case your BIOS/emulator jumps to 07C0:0000 instead of 0000:7C00 after loading the boot sector.

Code: Select all

main:
jmp 0000:main1
main1:
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7BFE
mov bp, sp
mov [bootdisk],dl
Microsoft is over if you want it.
Bietje
Member
Member
Posts: 100
Joined: Wed Apr 20, 2011 6:57 am

Re: Bootloader fails on a real pc

Post by Bietje »

DavidCooper wrote:
Bietje wrote:If I use mov [bootdisk], dl it triple faults (I tested on my main pc and it spams the first bootmessage of stage 1 10000 milion times)..
And if I do not use the disk number supplied by the bios in dl but use a static value like 0x0 for floppy or 0x80 it doesn't load the correct sectors..
Where is that going to in memory? 0? It looks as if it's probably messing up the first of the BIOS's interrupt vectors, and as that one gets triggered 18 times a second you're going to get a crash straight away. You need to set up the segment registers right at the start and pick an address to store the drive number where it isn't going to cause any harm.

Bochs probably doesn't bother to simulate real mode interrupts - it certainly doesn't appear to update the system timer variable in the BDA, so you're probably using memory you shouldn't and getting away with in Bochs by luck.
So what you are suggesting is that I should not reset my data segments to 0?
User avatar
Rusky
Member
Member
Posts: 792
Joined: Wed Jan 06, 2010 7:07 pm

Re: Bootloader fails on a real pc

Post by Rusky »

You do need to set your data segment to something known. Because of the org 0x7c00, you should probably just set it to 0. It should look something like this:

Code: Select all

cli

; initialize segment registers
xor ax, ax
mov ds, ax
mov es, ax

mov ss, ax
mov sp, 0x7c00

sti

mov [bootdisk], dl
; do stuff
; load from drive [bootdisk]
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bootloader fails on a real pc

Post by DavidCooper »

Bietje wrote:So what you are suggesting is that I should not reset my data segments to 0?
Actually I probably jumped the gun - I'll have a proper look at your code and not just assume it's as bad as it looked at first sight...

Setting the segments to 0 at the start is fine, by the way.
booted db 'GEBL has been loaded by the bios! Executing...', 0x0
Is this the message that appears 10000 million times? And where's the code that prints it out? All I can see is the call:-

Code: Select all

call println
and this:-

Code: Select all

;
; Print routines
;

%include 'boot/x86/println.asm'
No one's going to want to analyse the rest of your code carefully until they're sure there's no bug in your print routine.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
Bietje
Member
Member
Posts: 100
Joined: Wed Apr 20, 2011 6:57 am

Re: Bootloader fails on a real pc

Post by Bietje »

Hi,

I have fixed the spamming on of the message.
booted db 'GEBL has been loaded by the bios! Executing...', 0x0
Don't ask me how, it just was, after I did a few tests.

I use the following println routine:

Code: Select all

println:
	lodsb
	or al, al
	jz .return	; null byte found
	mov ah, 0x0E
	xor bh, bh	; page 0
	int 0x10
	jmp println

.return:
	mov al, 0x0A 	; new line
	mov ah, 0x0E
	xor bh, bh
	int 0x10

	mov al, 0x0D	; carrage return
	mov ah, 0x0E
	xor bh, bh
	int 0x10
	ret
You can find my entire project here.

I really apriciate your help!

I found an old hard disk and I'm going to try that now, maby it is just that it won't boot with and USB.

Greetings,
Bietje

edit:
When I try to read and load sector one, every thing is ok.. it just spams the welcome message. That was probaly the bug why it spammed earlier. When I try to read sector 2 it juust hangs..
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bootloader fails on a real pc

Post by DavidCooper »

Try this. If I'm understanding you correctly, everything's fine up to:-

Code: Select all

   jmp 0x7C0:0x200
I'd like you to add a bit of code just before that just to make sure, and also to add a bit of code to the start of the second sector to do the same thing. I want you to set ES to B800, DI to 0, AL to 65 and AH to 10, then send the contents of AX (a green capital A) to the top left corner of the screen with a stosw instruction. Do that just before the far jump. At the start of the second sector I want you to set AL set to 66 and to do another stosw - this should print a capital B next to the A if the second sector has loaded.

Also, is there a disk image available for me to look at - I prefer to read the machine code directly.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
Bietje
Member
Member
Posts: 100
Joined: Wed Apr 20, 2011 6:57 am

Re: Bootloader fails on a real pc

Post by Bietje »

Did you realized you may not use video memory in real mode?

But I moved the location of my welcome message to just before the jump, and that one does print correctly. But the print at the start of stage 2 does not print.. Even if I do not work with calls (and thus.. not with the stack), but move the code into my main routine..

I made a test project, which should just load a sector and execute it (just to keep overview, my main project does to many other things).

Sources of test project (were the jump fails as hard as with the bigger project) below. This one also has great success with emulators but great failure with real pc's and bioses.. Also there is a zip package added with source + flat bin executable so you can make your own hexdumps and stuff.

entry point

Code: Select all

[ORG 0x7C00]
[BITS 16]

_start: ; entry point
	cli
	jmp 0x0:.flush
.flush:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, 0x7BFE
	mov [bootdisk], dl
	sti


.reset:
	xor ax, ax
	mov dl, [bootdisk]
	int 0x13
	jc .reset

.read:
	mov ah, 0x2
	mov al, 1 ; read 1 sector
	xor cx, cx ; track 0
	mov cl, 2 ; read sector 2
	xor dx, dx ; head 0
	mov dl, [bootdisk]
	
	; setup buffer
	xor bx, bx
	mov es, bx
	mov bx, 8000h ; offset 8000 hex
	int 0x13
	jc .read
	or ah, ah
	jnz .reset

	; print a character
	mov al, 65
	mov ah, 0x0E
	xor bh, bh	; page 0
	int 0x10
	jmp 0x0:8000h

	bootdisk db 0

times 510 - ($ - $$) db 0
dw 0xAA55
stage2

Code: Select all

[ORG 0x8000]
[BITS 16]

	mov al, 66
	mov ah, 0x0E
	xor bh, bh	; page 0
	int 0x10

	jmp $

times 512 - ($ - $$) db 0
Attachments
testloader.zip
Sources + executable
(2.14 KiB) Downloaded 92 times
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bootloader fails on a real pc

Post by DavidCooper »

Bietje wrote:Did you realized you may not use video memory in real mode?
Do you realise that you can use video memory in real mode? I suggested that you do it that way to avoid extra possible register corruptions being introduced by the BIOS.
But I moved the location of my welcome message to just before the jump, and that one does print correctly. But the print at the start of stage 2 does not print.. Even if I do not work with calls (and thus.. not with the stack), but move the code into my main routine..
So it looks as if it isn't loading. Another way to make absolutely sure though would be to put a jump in at the start of the second sector and follow it with some ASCII. You can then add code before the far jump in the boot sector to read from the addresses where the ASCII should be and just copy them directly to the screen to see if they are there.
I can't attatch the binary image because it says the extension is not allowed, whatever extension I use..
In that case I can't check your code properly because I don't know assembler well enough to know exactly how it gets converted into the machine code that I understand.

Perhaps you could add some more code befor the far jump to collect the drive number from the place you've stored it in (I'm talking about the number passed to your code in DL by the BIOS) - you can then post it to the screen by putting it in AL with AH=10 (that's a decimal ten, by the way, as were the 65 and 66 I mentioned before for the capital A and B - you may want to convert them to hex) and then send AX directly to the screen as described earlier. You might then see a strange symbol on the screen, but just do a screen grab of it and I'll tell you what number value it must be. In case it's blank, inc AX and post it to the screen again two bytes further on in screen memory so that it turns into something visible.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
Post Reply