Two-stage bootloader issue

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
morgoth
Posts: 5
Joined: Mon Oct 13, 2014 3:56 am

Two-stage bootloader issue

Post by morgoth »

Hello,

This is my first post here and I am looking for some help as I am really stuck on something. I have tried many alternatives and spent a few days debugging to no avail.

Long story short, I have initially created a simple boot-loader that shows some graphics and then a very simple shell.
I then realized I am limited by the 512 bytes and cannot add any more functionality to it.
So, my solution was to create a two stage boot-loader. The first one would just read the second sector on the disk and load the second boot-loader, which now can be as long as I need it to be.

When I only have one single bootloader, everything works as expected. When I have two, the first one works, loads the second one and executes just the first few instructions from it, then I get a black screen. But I can see it jumps to a function that reads from keyboard as I can freely type stuff onto that screen.

This is the link for my repository: https://github.com/blidarescub/os-dev

The single bootloader is test.asm
The other two ones are the remaining files.

I can provide a boot image if necessary for reproducing the issue.

Thank you so much in advance
MrJonParr
Posts: 10
Joined: Sun Sep 14, 2014 2:10 am
Location: London, UK

Re: Two-stage bootloader issue

Post by MrJonParr »

Hi,

I'm learning this too, but it might be worth checking that all the stage2 loader is present, from the look at the code, this bit:

Code: Select all

Read_disk:
XOR AH, AH
INT 0x13
MOV BX, 0x8000 ; segment
MOV ES, BX
MOV BX, 0x0000 ; offset
MOV AH, 0x02 ; read function
MOV AL, 0x01 ; sectors - this might be wrong, trying to read from hd
MOV CH, 0x00 ; cylinder
MOV CL, 0x02 ; sector
MOV DH, 0x00 ; head
MOV DL, 0x80 ; drive - trying to read from hd
INT 0x13 ; disk int
JC Read_disk
JMP 0x8000:0x0000 ; buffer
Is it reading the entire stage2? Looks like you pad second_stage.asm to 1024 bytes but only read a single sector. Perhaps it's worth debugging and checking that after the read you see the entire stage2 bootloader in memory (maybe place a signature just like in the bootloader and see if you can see it at the end)?

Cheers,
Jon.
ExeTwezz
Member
Member
Posts: 104
Joined: Sun Sep 21, 2014 7:16 am
Libera.chat IRC: exetwezz

Re: Two-stage bootloader issue

Post by ExeTwezz »

Hi,

It seems like you're trying to load the second bootloader from the hard disk

Code: Select all

Read_disk:
XOR AH, AH
INT 0x13
MOV BX, 0x8000 ; segment
MOV ES, BX
MOV BX, 0x0000 ; offset
MOV AH, 0x02 ; read function
MOV AL, 0x01 ; sectors - this might be wrong, trying to read from hd
MOV CH, 0x00 ; cylinder
MOV CL, 0x02 ; sector
MOV DH, 0x00 ; head
MOV DL, 0x80 ; drive - trying to read from hd
INT 0x13 ; disk int
JC Read_disk
JMP 0x8000:0x0000 ; buffer
I don't recommend you to use hard disk right after you write your first bootloader. You should use floppy disk instead. And you're loading the second stage at 0x8000:0x0000 which equals to 0x0000:0x80000. It's better to load it at 0x0000:0x2000, for example.

Also, here is a link to a tutorial on loading sectors: http://www.osdever.net/tutorials/view/loading-sectors.
morgoth
Posts: 5
Joined: Mon Oct 13, 2014 3:56 am

Re: Two-stage bootloader issue

Post by morgoth »

Thanks for the quick replies.
MrJonParr wrote:Hi,

Is it reading the entire stage2? Looks like you pad second_stage.asm to 1024 bytes but only read a single sector. Perhaps it's worth debugging and checking that after the read you see the entire stage2 bootloader in memory (maybe place a signature just like in the bootloader and see if you can see it at the end)?

Cheers,
Jon.
It does not really matter the extra sector padding, as all the code fits neatly into the second sector. The third sector is just filled with 00's. So, first sector contains first boot-loader and second sector - second boot-loader. But good catch, thanks ;)
ExeTwezz wrote:Hi,

It seems like you're trying to load the second bootloader from the hard disk

I don't recommend you to use hard disk right after you write your first bootloader. You should use floppy disk instead. And you're loading the second stage at 0x8000:0x0000 which equals to 0x0000:0x80000. It's better to load it at 0x0000:0x2000, for example.

Also, here is a link to a tutorial on loading sectors: http://www.osdever.net/tutorials/view/loading-sectors.
Thanks for this remark, I have altered the code accordingly and I am still facing the exact same issue. I will now upload an .IMG floppy image on my github so that maybe someone can correlate the execution with the code and see where it hangs. I have no idea how to do that. All I can see is that the text cursor is left at the end of the first boot-loader's text, and it allows me to type R or I for reboot or interactive shell, and then executes the code accordingly. I't just the print functions that don't do anything. I initially thought it is about the video modes but I tried so many to no avail...

New code + boot image: https://github.com/blidarescub/os-dev/tree/devel
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Two-stage bootloader issue

Post by Brendan »

Hi,

For a start, when you pass control to the second stage all the segment registers (DS, ES, ...) are left unchanged, so in every place where you access data you access the wrong address (e.g. printing the string at "0x0000:INTRO" and not the string at "0x2000:INTRO").
morgoth wrote:Thanks for this remark, I have altered the code accordingly and I am still facing the exact same issue. I will now upload an .IMG floppy image on my github so that maybe someone can correlate the execution with the code and see where it hangs. I have no idea how to do that.
Learning how to use something like (e.g.) the debugger built into Bochs to debug your code is something that every OS developer must learn sooner or later.


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.
morgoth
Posts: 5
Joined: Mon Oct 13, 2014 3:56 am

Re: Two-stage bootloader issue

Post by morgoth »

Brendan wrote: For a start, when you pass control to the second stage all the segment registers (DS, ES, ...) are left unchanged, so in every place where you access data you access the wrong address (e.g. printing the string at "0x0000:INTRO" and not the string at "0x2000:INTRO").
Thanks, I think this is my problem and I will try to fix it.
But I thought that by using [ORG 0x2000:0x0000] the CPU will take care of the offsets...

It still doesn't make any sense to me why the first calls work:

Code: Select all

[BITS 16]
[ORG 0x2000:0x0000]

CALL Clear_screen         ; this works, it actually scrolls up the entire screen
CALL Draw_rect             ; this works, draws a rectangle pixel by pixel
CALL Delay                    ; waits a second
CALL Clear_screen         ; clears screen again
MOV SI, INTRO              ; from here it should load the address into SI and call the print function, which in the first boot-loader works perfectly. here it fails
CALL PrintShell
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Two-stage bootloader issue

Post by Brendan »

Hi,
morgoth wrote:
Brendan wrote: For a start, when you pass control to the second stage all the segment registers (DS, ES, ...) are left unchanged, so in every place where you access data you access the wrong address (e.g. printing the string at "0x0000:INTRO" and not the string at "0x2000:INTRO").
Thanks, I think this is my problem and I will try to fix it.
But I thought that by using [ORG 0x2000:0x0000] the CPU will take care of the offsets...
I'm surprised that the assembler doesn't give you a "bad origin" error. The "ORG" is used by the assembler to determine the offset of labels, etc. within the segment; and the assembler doesn't know or care how you've chosen to use segmentation (or even if your code is intended for 16-bit protected mode or 16-bit real mode).
morgoth wrote:It still doesn't make any sense to me why the first calls work:
The call instructions depend on CS (which is set by the "jmp 0x2000:0x0000" in the first stage) and not DS, ES, SS, etc.

Also, because these call instructions use a relative displacement they also don't depend on the origin - it's like "displacement = (origin + first_offset) - (origin + second_offset)", where the value of "origin" cancels itself out.
morgoth wrote:

Code: Select all

MOV SI, INTRO              ; from here it should load the address into SI and call the print function, which in the first boot-loader works perfectly. here it fails
It loads the offset of INTRO into SI; then (later) uses DS:SI as the address (where SI is the correct offset, but DS is not the correct segment). To fix it, just do something like this near your entry point:

Code: Select all

    mov ax,cs
    mov ds,ax
    mov es,ax

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.
morgoth
Posts: 5
Joined: Mon Oct 13, 2014 3:56 am

Re: Two-stage bootloader issue

Post by morgoth »

WOW!!

Thanks, Brendan!

It worked perfectly. After spending the whole weekend on this issue, I finally have a two-stage bootloader that works properly.

I deleted the ORG instruction in the second stage and used your advice on correctly initializing the segment registers.

Code: Select all

[BITS 16]

MOV AX,CS ; initialize
MOV DS,AX ; segments
MOV ES,AX ; correctly

CALL Clear_screen
CALL Draw_rect
CALL Delay
CALL Clear_screen
Now all is OK, I guess this question can be closed.
Thanks again for all your advices.
Post Reply