[BootBoot] Part 2: Boot from a floppy drive, load the 2nd sector, jump to it

This is my second post on BootBoot, the “boot loader” I am writing to load the real boot loader after displaying something on screen. I am writing this program for fun, and to learn the x86 assembly basics. I am trying to write one blog post per commit for me to remember what I’ve done next time I need to use assembly, and for any other assembly n00b out there who might be interested in reading my steps.

In this second post, I am going to extend the program of Part 1 to load the second sector, jump to it and clear the screen with a different color after that. If the displayed color is the new one I can validate the jump was successful.


More Debugging Tools:

In my last post I used qemu and nasm (assembler) for everything but as the complexity of the program slightly increased I needed to debug my code from time to time. For that I used a disassembler and GDB and added more rules in my Makefile:

to disassemble the code with the ndisasm disassembler and:

to debug it.

When I run qemu with make debug I can open gdb in a different terminal and the process will be automatically attached. Then, I can set a breakpoint in 7c00(remember this is the address where the assembler starts reading, explained in Part1), and step into the code.

I use the following .gdbinit in my bootboot directory to make sure GDB is in 16-bit mode and shows x86 assembly:

Example use:

I set a breackpoint in 0x7c00 and then stepped to next command using si. GDB displays the names of the registers like we were in 32bit mode ( eax is the 32bit ax and esp is the 32bit sp). I think this shouldn’t happen but I haven’t found how to change it yet… 😇 Since it steps correctly and can recognize the 8086 architecture I just ignored that initial “e” in registers names.


Code additions:

Let’s see how the program of Part 1 (check the end of the post) can be extended to read the 2nd sector and clear the screen with another color.

First of all we need to modify clearscreen to read the color from ax but not set it: we need to set it before we call it, to call it with different colors each time.

Therefore we change clearscreen from Part 1 to be:

(we use push and pop to preserve the previous ax content).

and we set the color in ax before calling clearscreen right after the int 10h interrupt (see Part 1):

Now let’s write the 2nd clearscreen that changes the cyan color to purple at the end of the program:

In this snippet we set another color in ax (5 is a purple) and we call clear screen. Then we use an infinite loop similar to that of Part 1 which we must remove now to prevent the program from exiting before we see the color.

Next step is to load the second sector of the boot device and jump to it. We are going to use some segment registers for that (see Part 1 and links about x86 segmentation below).

First of all we initialize the segment registers to 0 (we can’t assign values to them directly as we’ve seen in Part 1, so we must use ax for that).

 
Then, we need to store the value that is currently in dl (lower bits of dx).

When the program execution begins, dl contains the device number from which the program was loaded (and the first sector in case of floppy disk). Then it gets overwritten while dx is used to store other values. In order to save the initial value we go somewhere at the end of the code and reserve one byte to save the initial value of dl. We do that in the end of the program to avoid jumping around it:

db is used to define a byte and fill its bits with 0.

Then we only need to do:

to save the drive number at initialization.

At this point we can load the second sector from the boot device and jump to it.

To do so, we need to use the interrupt 13h that is for disk io and call the bios routine that loads sectors.

Let’s see the documentation for interrupt 13H again:
It seems that we need Int 13/AH=02 - DISK to read sector(s) into memory from the list.

And according to the Int 13/AH=02 bios routine documentation:

We need to fill the following registers:

and so we clear ax and we use it to also clear ds and:

  • We set 02h in ax,
  • we set 1 in al as we want to read one sector,
  • we set 0 to ch (lower 6 bits of cylinder number) because we don’t need them,
  • we set 2 in cl because we want to use the 2nd sector
  • we set 0 in dh (head number),
  • and the drive number we saved at the beginning to dl.
  • Then we fill bs with our data: what follows the sector_2 label.
  • If there’s no carry in cf, then we jump to sector_2, otherwise we enter the infinite loop so that we can see the color of the first clearscreen (cyan) and know that we failed.

The code:

With that final change the program should clear the screen in cyan at the beginning and then in purple. If jump is successful we should see purple. If not, we see cyan.


Results:

Should be something like this:

On failure we should see the screen we were seeing in Part 1.


Code:

Makefile:

 
bb.asm:

 
.gdbinit:

That’s it! In the next post, we are going to use the keyboard!


Links:

Previous posts on BootBoot:
[BootBoot] Part 1: Boot from a floppy drive and clear the screen

Other:
[1]: Ralf Brown’s Interrupt List
[2]: Mode 13h in Wikipedia
[3]: X86 memory segmentation
[4]: NASM – The Netwide Assembler
[5]: The Netwide Disassembler, NDISASM
[6]: Int 13/AH=02h: Read disk sectors into memory

Leave a Reply

Your email address will not be published. Required fields are marked *