Some newbie problem in bootloader

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
hypeboyz
Posts: 8
Joined: Wed Nov 10, 2010 2:29 am

Some newbie problem in bootloader

Post by hypeboyz »

As I'm writing a very simple bootloader, I got a very weird problem.
So far I have 2 files namely boot.s which is to load stuffs from floppy and setup.s for testing the bootloader. My Makefile goes like this:

Code: Select all

AS=as
LD=ld
LDFLAGS_16=-s -Ttext 0 --oformat binary
LDFLAGS_SYS=-s -x -m elf_i386 -e fin -Ttext 0 -M
CC=gcc

boot:   boot.s
        $(AS) -o boot.o ./boot.s
        $(LD) $(LDFLAGS_16) -e start -o $@ ./boot.o

setup:  setup.s
        $(AS) -o setup.o ./setup.s
        $(LD) $(LDFLAGS_16) -e fin -o setup ./setup.o 

image:  boot    setup
        #dd if=./boot of=./image 
        cat ./boot ./setup >./image

clean:  
        rm ./boot ./setup ./*.o 
And my OS Dev book (a book written by a Japanese) took a very slow approach to load: one sector each int 0x13. So I also use this method to load:

Code: Select all

#some initialization and output stuff and ljmp 0x0c70 etc. 
#initialise registers for int 0x13
        movw    $SYSSEC, %ax
        movw    %ax, %es
        xor     %di, %di
        movb    $0x02, %cl
        xor     %ch, %ch
        xor     %dx, %dx
        xor     %bx, %bx
loading:
        movb    $2, %ah
        movb    $1, %al

        int     $0x13
        jc      retry
        xor     %di, %di

#loading sectors on other headers or cylinders
        movw    %es, %ax
        add     $0x20, %ax
        movw    %ax, %es
        inc     %cl
        cmp     $18, %cl
        jbe     loading
        movb    $1, %cl
        inc     %dh
        cmp     $2, %dh
        jb      loading
        xor     %dh, %dh
        inc     %ch
        cmp     $10, %ch
        jb      loading
#All done, output success info
        movw    $BOOTSEC, %ax
        movw    %ax, %es
        movw    $7, %cx
        movw    $0x1105, %dx
        movw    $0x000c, %bx
        movw    $ok_msg, %bp
        movw    $0x1301, %ax
        int     $0x10

        ljmp    $SYSSEC, $0

#if something goes wrong with loading
#retry 5 times
retry:
        inc     %di
        cmp     $5, %di
        jae     error_loading
        xor     %al, %al
        xor     %dl, %dl
        int     $0x13
        jmp     loading

hlt:
        jmp     hlt

#if things just doesn't go well after
#repeated retry
#output error info and jmp to hlt
This ljmp never succeed. When I inspect memory in gdb by x 0x10000 and area next to it, it turns out nothing's been loaded. And when I commented the successful loading output codes out and check registers in gdb, it shows that every register worked in the expected way. The cylinders register was 0x0a, head register was 0x00, sector register was 0x01, es was added by the exact number of sectors offset and di has never been set. So I cannot figure out what the problem is.
In addition, I'm using the qemu and running the command like:

Code: Select all

qemu-system-i386 -cpu 486 -fda ./image -boot a -s
Also I've another question, the ld options T specifies the linker script, and what does the Ttext mean, and what is the 0 after that?
Thank you beforehand!
User avatar
wichtounet
Member
Member
Posts: 90
Joined: Fri Nov 01, 2013 4:05 pm
Location: Fribourg, Switzerland
Contact:

Re: Some newbie problem in bootloader

Post by wichtounet »

Can you show what you have in $SYSSEC, I don't see this anywhere. Do you have taken into account that if you have es:bx = 0x1000:0x0, it means the address 0x10000 ?
hypeboyz wrote:Also I've another question, the ld options T specifies the linker script, and what does the Ttext mean, and what is the 0 after that?
Thank you beforehand!
I cannot answer your main question, but at least, I can answer this one. It just put the section .text at the absolute address 0x0. You can also use Tbss and Tdata. There are shortcuts to the --section-start=sectionname=org option.
Thor Operating System: C++ 64 bits OS: https://github.com/wichtounet/thor-os
Good osdeving!
hypeboyz
Posts: 8
Joined: Wed Nov 10, 2010 2:29 am

Re: Some newbie problem in bootloader

Post by hypeboyz »

wichtounet wrote:Can you show what you have in $SYSSEC, I don't see this anywhere. Do you have taken into account that if you have es:bx = 0x1000:0x0, it means the address 0x10000 ?
hypeboyz wrote:Also I've another question, the ld options T specifies the linker script, and what does the Ttext mean, and what is the 0 after that?
Thank you beforehand!
I cannot answer your main question, but at least, I can answer this one. It just put the section .text at the absolute address 0x0. You can also use Tbss and Tdata. There are shortcuts to the --section-start=sectionname=org option.
Thanks wichtounet
SYSSEC is 0x1000 and yes, I just want to load setup stuff into 0x10000. I think I should attach all files.
Attachments
myos.tar.bz2
(2.27 KiB) Downloaded 95 times
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Some newbie problem in bootloader

Post by Brendan »

Hi,
hypeboyz wrote:When I inspect memory in gdb by x 0x10000 and area next to it, it turns out nothing's been loaded.
There are only about 4 things that could be going wrong:
  • The BIOS returns an error. In this case you end up at "error_loading" so you'd (hopefully) know if this was happening.
  • The BIOS loads the right sectors to the wrong address. If you're sure that 0x1000:0x0000 is the right address then this isn't happening.
  • The BIOS loads the wrong sectors to the right address. For example; maybe you're trying to boot from hard disk or the second floppy disk but you've "accidentally" hard-coded "DL = device number = 0" into your code for no sane reason and its reading sectors from the wrong device.
  • The BIOS loads the right sectors to the right address. In this case maybe the problem is that the sectors weren't stored on the disk properly in the first place (e.g. the sectors that should contain your second stage are actually full of zeros).
If we assume the first 2 cases aren't happening; then that leaves the last 2 problems.

To determine what is happening; I'd start by using some other tool to check that the sectors contain what they should (e.g. "hexdump image").

Note: When the BIOS starts your boot loader it sets DL to the device number of the device you booted from. By storing this device number somewhere and using the same device number to load sectors, your boot loader will automatically/correctly handle booting from the second floppy disk (or second hard drive, or third floppy disk or fourth hard drive or...).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: Some newbie problem in bootloader

Post by Antti »

Code: Select all

BOOTSEC=0x07c0
SYSSEC=0x1000

.code16
.text

.global start
start:
	ljmp	$BOOTSEC, $go
go:
	movw	%cs, %ax
	movw	%ax, %ds
	movw	%ax, %ss
	movw	%ax, %es
	movw	%ax, %fs
	movw	%ax, %gs
	movw	$400, %sp

	...
	...
I took a look at your code. Your stack setup will cause very serious problems. I did not read further because this could cause all the problems you have. Make sure your stack will not trash code being used.
kutkloon7
Member
Member
Posts: 98
Joined: Fri Jan 04, 2013 6:56 pm

Re: Some newbie problem in bootloader

Post by kutkloon7 »

I don't know exactly how difficult it is to get a debugger working with QEMU, but my first reaction would be to debug to the point of the interrupt, and inspect everything there very well, especially the input and output registers of the interrupt you're using and compare it with the documentation available.

As Antti said, you may want to reconsider your stack setup. Debuggers are ideal to discover problems in the bootloading stage (and also a really good exercise to read assembly code and really understand what's going on).
mrstobbe
Member
Member
Posts: 62
Joined: Fri Nov 08, 2013 7:40 pm

Re: Some newbie problem in bootloader

Post by mrstobbe »

To point you in the right direction with the whole stack thing: http://wiki.osdev.org/Memory_Map_(x86). Remember... push to the stack decrememts SP; pop adds to it.
hypeboyz
Posts: 8
Joined: Wed Nov 10, 2010 2:29 am

Re: Some newbie problem in bootloader

Post by hypeboyz »

The BIOS loads the wrong sectors to the right address. For example; maybe you're trying to boot from hard disk or the second floppy disk but you've "accidentally" hard-coded "DL = device number = 0" into your code for no sane reason and its reading sectors from the wrong device.
The BIOS loads the right sectors to the right address. In this case maybe the problem is that the sectors weren't stored on the disk properly in the first place (e.g. the sectors that should contain your second stage are actually full of zeros).
As you've seen in my run.sh, I set the fda to load the image. I supposed first floppy driver should be the the driver 0. Umm... I guess it probably cause the problem.
I took a look at your code. Your stack setup will cause very serious problems. I did not read further because this could cause all the problems you have. Make sure your stack will not trash code being used.
You're right, I forgot add 0x onto 400. But the problem seems remained same even if I set stack to the 0x400. It's a value that I've learned from the linux 0.12 codes in setting temporary stack. And I wondered if this malpositioned stack is the cause since my codes are so short and I've striped all the headers off.
I don't know exactly how difficult it is to get a debugger working with QEMU, but my first reaction would be to debug to the point of the interrupt, and inspect everything there very well, especially the input and output registers of the interrupt you're using and compare it with the documentation available.
I commented out codes after 0x13 and set a dead loop there to inspect the affected registers and every registers worked properly. I've even calculated how many sectors has been read and the expected value of es for these sectors. Everything's okay.

Once more thanks to you all. I used to read linux kernel source codes and understand the most core part of it, buddy system slab allocation and other gdt idt protected mode stuff and I thought these knowledge would be adequate to write a kernel of my own. Apparently there's still a long way to go.
mrstobbe
Member
Member
Posts: 62
Joined: Fri Nov 08, 2013 7:40 pm

Re: Some newbie problem in bootloader

Post by mrstobbe »

You're right, I forgot add 0x onto 400. But the problem seems remained same even if I set stack to the 0x400.
We've been pointing out that you're clobbering BIOS data/IVR. You can't set the stack to 0x0400. Again, refer to http://wiki.osdev.org/Memory_Map_(x86), remember that the stack grows upward, and pick a different stack location.
EDIT: Just bothered to notice that you are using CS 0x07C0, still you might be clobbering your own code with your stack setup. 0x07C0:0x0400 means that there's only 512 bytes for the stack before you start clobbering your own bootsector code.
hypeboyz
Posts: 8
Joined: Wed Nov 10, 2010 2:29 am

Re: Some newbie problem in bootloader

Post by hypeboyz »

mrstobbe wrote:
You're right, I forgot add 0x onto 400. But the problem seems remained same even if I set stack to the 0x400.
We've been pointing out that you're clobbering BIOS data/IVR. You can't set the stack to 0x0400. Again, refer to http://wiki.osdev.org/Memory_Map_(x86), remember that the stack grows upward, and pick a different stack location.
EDIT: Just bothered to notice that you are using CS 0x07C0, still you might be clobbering your own code with your stack setup. 0x07C0:0x0400 means that there's only 512 bytes for the stack before you start clobbering your own bootsector code.
Um.. Yep? I'm sure the stack grows downwards as your former post said. See, there's no explicit operations that involves stack like call push pop etc. Maybe interrupt would have use it, but is it possible that one int 0x10 and one int 0x13 could have depleted all 512 bytes? Anyway I've tried changing the sp to 0xffff - 0x7c00 = 0x83ff, just below the 0x10000 where I loaded my setup.s and conventionally usable according to the mem map. However the result is still disappointing and as the gdb indicated, the sp remained the same after these two int. So yes the original stack at 0x7c00 + 400 may probably overlap my codes and this setting is exactly the potential problem, but since the stack won't grow in my code and my code never reach that far (not even 100 bytes in size without the 0xaa55 label) the stack may not be the cause I think.
mrstobbe
Member
Member
Posts: 62
Joined: Fri Nov 08, 2013 7:40 pm

Re: Some newbie problem in bootloader

Post by mrstobbe »

hypeboyz wrote:Um.. Yep? I'm sure the stack grows downwards as your former post said. See, there's no explicit operations that involves stack like call push pop etc. Maybe interrupt would have use it, but is it possible that one int 0x10 and one int 0x13 could have depleted all 512 bytes? Anyway I've tried changing the sp to 0xffff - 0x7c00 = 0x83ff, just below the 0x10000 where I loaded my setup.s and conventionally usable according to the mem map. However the result is still disappointing and as the gdb indicated, the sp remained the same after these two int. So yes the original stack at 0x7c00 + 400 may probably overlap my codes and this setting is exactly the potential problem, but since the stack won't grow in my code and my code never reach that far (not even 100 bytes in size without the 0xaa55 label) the stack may not be the cause I think.
Well, it was just a thought (originally spurred by the fact that I falsely assumed you were jumping to 0x0:0x7C00+go; which is why the edit).

Anyhow... looking over the code again I don't see anything obviously wrong. BTW, your Makefile provided in myos.tar.bz is a bunch of binary, and there was a typo (ax instead of %ax), but after fixing that stuff and compiling, a hexdump of the resulting shows that your bootsector binary is not padded to 512 bytes. Therefore, both objects are being stored in the same sector after the cat call.
hypeboyz
Posts: 8
Joined: Wed Nov 10, 2010 2:29 am

Re: Some newbie problem in bootloader

Post by hypeboyz »

Well, it was just a thought (originally spurred by the fact that I falsely assumed you were jumping to 0x0:0x7C00+go; which is why the edit).

Anyhow... looking over the code again I don't see anything obviously wrong. BTW, your Makefile provided in myos.tar.bz is a bunch of binary, and there was a typo (ax instead of %ax), but after fixing that stuff and compiling, a hexdump of the resulting shows that your bootsector binary is not padded to 512 bytes. Therefore, both objects are being stored in the same sector after the cat call.
I've attached the result of hexdump -C image. Maybe I got something wrong in compressing, but anyway I don't figure out anything wrong with padding.
Attachments
hexmap.txt
(1.23 KiB) Downloaded 162 times
mrstobbe
Member
Member
Posts: 62
Joined: Fri Nov 08, 2013 7:40 pm

Re: Some newbie problem in bootloader

Post by mrstobbe »

The problem is that...

Code: Select all

.org 510
... does not actually pad anything out. All it does is tell the compiler what CS/IP to expect when it makes addressing assumptions. You need something like (in nasm/yasm sytax):

Code: Select all

padding: db times 510-($$-$) db 0
I have no idea what this looks like in GAS syntax but basically it just means that, for as many times as we haven't filled up to 510 bytes from the start of the assembly, fill with 0's. I've never become familiar with gas syntax (and it's not even remotely on my priority list).

Basically, you just need boot.s to fill the first 512 byte sector, and setup.s to come after that. If you do that, you should be good (hypothetically).
User avatar
Minoto
Member
Member
Posts: 89
Joined: Thu May 12, 2011 7:24 pm

Re: Some newbie problem in bootloader

Post by Minoto »

mrstobbe wrote:The problem is that...

Code: Select all

.org 510
... does not actually pad anything out. All it does is tell the compiler what CS/IP to expect when it makes addressing assumptions. You need something like (in nasm/yasm sytax):

Code: Select all

padding: db times 510-($$-$) db 0
I have no idea what this looks like in GAS syntax but basically it just means that, for as many times as we haven't filled up to 510 bytes from the start of the assembly, fill with 0's. I've never become familiar with gas syntax (and it's not even remotely on my priority list).

Basically, you just need boot.s to fill the first 512 byte sector, and setup.s to come after that. If you do that, you should be good (hypothetically).
False. You might want to add reading the gas documentation to your priority list to avoid spreading further misinformation.
Those who understand Unix are doomed to copy it, poorly.
mrstobbe
Member
Member
Posts: 62
Joined: Fri Nov 08, 2013 7:40 pm

Re: Some newbie problem in bootloader

Post by mrstobbe »

Then don't know what to tell you. Sorry. I made it clear that I didn't know GAS syntax, and the thread is dead besides me, so don't be snippy about it.
Post Reply