Page 1 of 1
Some newbie problem in bootloader
Posted: Wed Nov 06, 2013 6:12 pm
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!
Re: Some newbie problem in bootloader
Posted: Thu Nov 07, 2013 2:46 am
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.
Re: Some newbie problem in bootloader
Posted: Thu Nov 07, 2013 7:37 pm
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.
Re: Some newbie problem in bootloader
Posted: Fri Nov 08, 2013 2:34 am
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
Re: Some newbie problem in bootloader
Posted: Fri Nov 08, 2013 5:04 am
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.
Re: Some newbie problem in bootloader
Posted: Fri Nov 08, 2013 5:39 am
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).
Re: Some newbie problem in bootloader
Posted: Fri Nov 08, 2013 8:24 pm
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.
Re: Some newbie problem in bootloader
Posted: Mon Nov 11, 2013 1:25 am
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.
Re: Some newbie problem in bootloader
Posted: Mon Nov 11, 2013 1:34 am
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.
Re: Some newbie problem in bootloader
Posted: Mon Nov 11, 2013 6:46 pm
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.
Re: Some newbie problem in bootloader
Posted: Mon Nov 11, 2013 7:51 pm
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.
Re: Some newbie problem in bootloader
Posted: Tue Nov 12, 2013 8:41 pm
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.
Re: Some newbie problem in bootloader
Posted: Tue Nov 12, 2013 10:09 pm
by mrstobbe
The problem is that...
... 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):
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).
Re: Some newbie problem in bootloader
Posted: Tue Nov 12, 2013 10:49 pm
by Minoto
mrstobbe wrote:The problem is that...
... 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):
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.
Re: Some newbie problem in bootloader
Posted: Tue Nov 12, 2013 11:00 pm
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.