Page 1 of 1
Bootloader Only Works On Bochs
Posted: Sun Apr 27, 2003 10:24 pm
by Xeon
Hello everyone.
I've programmed my own bootloader (please don't ask me why I don't just use GRUB), but I'm having a problem. For some odd reason, it only works on Bochs and not on a real PC. On Bochs it boots up just fine, but on a real PC it only displays the first message ("Booting ToriX OS") and then reboots (which I think means it encountered a triple fault - whatever the heck that is). The flow of my bootloader is:
Set up a stack, enable the A20 gateway, load a temporary GDT, switch to protected mode, switch to unreal mode, step up a stack, load the second half of the bootloader from the floppy, load the kernel from the floppy to the 1MB mark, jump to the second half of the bootloader, detect that the user is using a 486+ CPU (I'm planning on using the invplg instruction), jump back into protected mode, set up a new stack, and finally jumping to the kernel at the 1MB mark.
I believe that the real PC is triple faulting when I jump to unreal mode, but I'm not sure. Please don't flame me for being stupid, I'm an assembly newbie and have just finished reading Assembly Language Step-by-Step (I've just gotten the Intel reference manuals).
Attached is the source code. macros.def contains the print macro which points to print_msg.
Please help me out! I will forever be in debt to you.
-Xeon
[attachment deleted by admin]
Re:Bootloader Only Works On Bochs
Posted: Mon Apr 28, 2003 1:03 am
by distantvoices
Code: Select all
unreal32:
; Load the data selector into ds, es, and ss:
mov ax, DATA_SELECTOR --> pls use AX
mov ss, ax SEGMENT Registers are
mov ds, ax 16 bits wide.
mov es, ax
;mov fs, ax
;mov gs, ax
; Switch back to real mode (but this time with segments larger than
; 64Kb:
mov eax,cr0 ; -->I think you should do this.
and al, 0xFE ; Unset the protected mode enable bit...
mov cr0, eax ; ...and write it back.
jmp dword 0x07C0:unreal-0x7C00 ; Go back to 16-bit mode.
have a look at it. I have added comments and some
recommendations.
And it is ok to write a bootloader
It is a learning experience. I have done it too prior to grub.
Re:Bootloader Only Works On Bochs
Posted: Mon Apr 28, 2003 4:07 pm
by Xeon
That might have solved some problems, but it's still not working on a real PC. When I just change the eax's to ax's the real PC still triple faults. When I just add the mov eax, cr0 the real PC no longer triple faults, but hangs at the "Booting ToriX OS" text. When I add both, needless to say, the real PC triple faults. All fixes work fine on Bochs...
What the heck is going on!?
Re:Bootloader Only Works On Bochs
Posted: Mon Apr 28, 2003 6:42 pm
by slacker
i never really liked using bochs unless i encountered a problem that i had no idea how to fix. i think you should take apart your code and put it back together piece by piece or place halts in your code at certain places so you know where the triple fault occurs. if you dont know where the error occurs then you'll spend a longer timer trying to fix it so i say take it apart and put it back together since a bootloader tends to be relatively small....
Re:Bootloader Only Works On Bochs
Posted: Mon Apr 28, 2003 8:03 pm
by Xeon
Ok. I've traced the problem down to read_floppy (using none other than 'jmp $'). I also noticed that I hear the floppy try to read something for like half a second and then dies. The code doesn't even get to print a dot if I'm not mistaken. Oi vey.
Re:Bootloader Only Works On Bochs
Posted: Mon Apr 28, 2003 8:29 pm
by Curufir
Ok, seeing as you took time out to narrow down the problem area I took time out to glance at the code
.
Remember that BOCHS emulates a perfect floppy drive, ie it will never produce a read/write error from a disk image. Now on a real floppy drive you'll get errors, plenty of them, and you should really try to reset the drive
before the first read operation.
In your code you try the read, assuming there's an error you then reset the drive. There's nothing wrong with this scheme (Although I'd be reseting the drive before the read). First time through the read_floppy routine you're using BX to represent start sector, you then push that value (And also put it into CX) before using BX to hold the destination offset for the BIOS read function, 0x8000 in your code.
Now assuming there's an error first time through the code you jump back to .try_again after reseting the drive, once again there's no inherent problem with that, but what value of BX are you using when you go back through the read the second time? Yup, 0x8000
. Things will get real wierd at this point.
There may be other errors, but if it works on BOCHS and not real hardware then this is a prime suspect as to why not.
Hope that helps.
Re:Bootloader Only Works On Bochs
Posted: Tue Apr 29, 2003 1:21 am
by Pype.Clicker
btw, i don't see you setting up DS to a known value before you load the GDT. As the bootsector may be loaded at 0x7c0:0000 or 0x0000:0x7c00 depending on the bios you should have
as your very first instructions...
btw, i don't see why you are jumping to 0x7c0:unreal-7c00, as you assumed the code was starting at [org 7c00] ... just use jmp 0x000:unreal
btw, i suggest you add a small checksum of your kernel before you jump to it (just to make sure it loaded properly)
Re:Bootloader Only Works On Bochs
Posted: Tue Apr 29, 2003 4:07 pm
by Xeon
Thanks a bunch everyone. All your comments are valid and have helped me, but it still isn't working. I think I might need to completely rewrite read_floppy which was taken from geist's newOS. Whatever I do just isn't cutting it.
I'm about to go into a series of jmp $'s after each and every instruction and reboot to determine the problem. I promise you, I've been trying to figure out this problem for almost a month. It really is quite discouraging...
The bugfixed code:
Code: Select all
; Read from the floppy (thanks geist):
read_floppy:
sti
push bx
push cx
.try_again:
mov al, 0x13 ; Read a maximum of 18 sectors.
sub al, bl ; Substract the first sector (to prevent
; wrap-around).
xor ah, ah ; Don't read more then required, VMWare doesn't
; like that.
cmp ax, cx
jl .shorten
mov ax, cx
.shorten:
;; RELOAD CX AND BX WITH THE INITIAL VALUES BEFORE CONTROL WAS PASSED TO
;; READ_FLOPPY. THEN PUSH BACK ON THE STACK TO REPOP THEM OFF WHEN DONE:
pop cx
pop bx
push bx
push cx
mov cx, bx ; Sector/cylinder number to read from.
mov bx, 0x8000 ; Buffer address.
mov ah, 0x2 ; Command 'read sectors'.
push ax
int 0x13 ; Invoke the BIOS => The computer reads the
; floppy.
pop ax ; Should return number of transferred sectors
; in al but VMWare 3 clobbers it, so we
; (re-)load al manually.
jnc .success ; No error => proceed as usual.
dec byte [retry_count]
jz .fail
xor ah, ah ; Reset the disk controller.
int 0x13 ; Invoke the BIOS => the floppy is read from.
;; CHEAP WAY TO FIX THE "BX'S VALUE STAYS AT 0x8000" (but being used to debug):
jmp .fail
;jmp .try_again ; Retry.
.success:
mov byte [retry_count], 3 ; Reload retry_count.
print dot
mov esi, 0x8000 ; Source.
xor ecx, ecx
mov cl, al ; Copy the number of read sectors (al)...
shl cx, 0x7 ; ...of size 128*4 bytes...
rep a32 movsd ; ...to destination (edi).
pop cx
pop bx
xor dh, 0x1 ; Read: next head.
jnz .bar6
inc bh ; Read: next cylinder.
.bar6:
mov bl, 0x1 ; Read: sector 1.
xor ah, ah
sub cx, ax ; Substract the number of read sectors.
jg read_floppy ; Sectors left to read?
cli
ret
.fail:
; Print an error message, wait for a keypress, and reboot:
print read_error_msg
print reboot_msg
xor ax, ax
int 0x16 ; Invoke the BIOS => the computer waits for a
; key.
int 0x19 ; Invoke the BIOS => the computer reboots
hlt ; Halt the CPU (if we even get here, that is).
Re:Bootloader Only Works On Bochs
Posted: Tue Apr 29, 2003 4:44 pm
by Pype.Clicker
a few tips:
- make use of the VRAM as copy buffer: it'll be easier to see if loading is made properly
- write a small keyboard-polling function to force breakpoints in your code
Re:Bootloader Only Works On Bochs
Posted: Tue Apr 29, 2003 5:57 pm
by Curufir
Ok, you've exacerbated the problem while trying to fix it. All you actually needed to do to remove the BX problem was add two lines before jumping back to the top of the read_floppy procedure.
Code: Select all
dec byte [retry_count]
jz .fail
xor ah, ah ; Reset the disk controller
int 0x13
pop cx ; Restore cx and bx values from the stack
pop bx
jmp .read_floppy ; Retry the read
Now that's just solving a general programming fault (Ie losing track of variables you are keeping on the stack), there may be others. Try adding the 2 pops to the original read_floppy procedure you posted and see what happens.
I'm still working on the hypothesis that:
a) The original read_floppy has no other errors (I really don't have time to go through line by line atm).
b) It really is the disk read error that's causing the problem (And it would definitely have caused a problem).
**
Apologies if you read this before the edit, had this nagging feeling I had something to correct today, finally figured it out a few minutes ago ;D.
Re:Bootloader Only Works On Bochs
Posted: Wed Apr 30, 2003 6:23 pm
by Xeon
Haha, I did read it before the edit, but I figured out what you were trying to say.
It didn't work, but thanks anyways. It solves that problem, however...dispite it still not working. I would use prints or some "keyboard-polling function", but I can't fit any more code/data into the first stage without overflowing the 512 byte limit.
Re:Bootloader Only Works On Bochs
Posted: Thu May 01, 2003 2:20 am
by Pype.Clicker
Shorten your message (after all, everything you need is a proof a stage has been reached), maybe use the "print string" BIOS function instead of a loop of printchars, drop your "unused entry" in your GDT, and maybe you can push your "unreal mode setup" in the second (or third) sector if you're still short of a few bytes. (after all, everything you *really* need in the bootsector is loading the remaining of the bootloader, don't you
maybe you can also try
"call near <x>" instead of "call <x>"
and some "mov bx,byte 1" instead of "mov bx,1"