http://giulio.hewle.com/gstuff/OS/1_Developing_a_simple_bootloader.txt

1 The boot process
------------------


        1.1 Pressing the power button
        -----------------------------
        Whenever the power button is pressed, the wires connected to it send an
electric signal to the motherboard. Depending on that signal, the Power Supply
Unit (PSU for short) begins to let power circulate  or not.

The signal consist of a single bit of data. If the bit is HIGH, the PSu receives
an activacting signal; on the contrary, in case the bit is LOW the PSU does not
supply any power.

Ok -- we hit the power button, the PSU has received our HIGH value bit and has
started to supply power. Once the power amount is enough, the PSU then sends the
'power_good' signal to the Basic Input Output System (BIOS).



        1.2 Into the BIOS
        -----------------
        Among others, the BIOS basically provides some services of general use:
they include Interrupt services, checks for hardware, Setup Utilities and the
Interrupt Vector table (IVT).

Once started working, the BIOS must look for some sort of OS by executing
Interrupt 0x19 to attempt to find a bootable device. The BIOS keeps seeking for
an OS until one is found or no more devices are available (INT 0x19 returns),
then halts the system.


                1.2.1 Quick look at Interrupts mechanism
                ----------------------------------------
                Basically, an interrupt is a subroutine available (globally) for
        execution from many different programs.
        All interrupts are stored starting from address 0x0 into a table (IVT).

        Interrupts are called 'by address', maning that the code
                int 0x17
        will call the 17th interrupt, the one stored at address 0x17 in the IVT.

        If a non-existent interrupt routine is called, say 0x99, the system
        crashes causing a reboot (or halt).




        1.3 What does the power_good signal does?
        -----------------------------------------
        Once the BIOS has successfully received the 'power_good' signal sent by
the PSU, it firstly initializes the Power On Self Test (POST). The POST process
is resopnsible for checking a good amount of power is supplied as well as all
devices (i.e. keyboard, serial ports, whatever) are installed and the memory is
not corrupted.

The POST then places a jmp instruction at the very beginning of the memory and
loads the BIOS at the end. The processor's Intruction pointer chip select
(CS_IP), active LOW, is set active and the processor actually takes control.

The processor executes sequantially all the intructions that are loaded into the
memory starting from address 0x0, which is filed with a jmp intruction to
address 0xFFFFF0 (end of memory), where the BIOS has been previously loaded.

The BIOS actually starts working. Here we go!




        1.4 BIOS Interrupts (0x19 in particular)
        ---------------------------------
        Sooner or later, the BIOS gets to the point of calling interrupt 0x19.
Interrupt 0x19 is the Bootstrap Loader interrupt, which warm-reboots the system
without clearing meomory nor IVT. The instruction is read from the first sector
of the first hard disk, Sector 1 / Head 0 / Track 0 (S/H/T 1/0/0 for shortening
up or C/H/S 0/0/1 as Track can also be Cylinder).


                1.4.1 Sectors, Heads and Tracks
                -------------------------------
                * Sector: represent a group of 512 bytes (S1 from 0 to 511,
                          S2 from 512 to 1023, etc.)
                * Head:   is the 'side' fo the disk; 0 is the front side, 1 the
                          back one. Some disks have only one side (H0).
                * Track:  diffcoult to explain, is a thin circular strip which
                          contains magnetic regions of written data.


                1.4.2 Notes about bootloading
                -----------------------------
                First to know, the bootsector is located (on a bootable device)
        at address 0x7C00; no news that INT 0x19 points right there.

        Now, little trick! On some systems, warm reboot is activated by putting
        0x1234 at address 0x0040:0072 and jumping to 0xFFFF:0.

        Cold reboot storing 0x0 instead.



        1.5 Alright, lets code something...
        -----------------------------------
        But first, we need some extra stuff


                1.5.1 Bootloaders. Life and miracles of one
                -------------------------------------------
                Bootloaders, as the name sharply suggests, boots something.

        More precisely, what a bootloader is expected to do is:
                * reside in the Master Boot record (MBR)
                * be in the first sector of the disk (C/H/S 0/0/1, remember?)
                * be _exactly_ of the size of a single sector (thus 512 bytes)
                * be loaded in the BIOS at address 0x7C00


Ok, we are READY. Let's start!

Always remember we are at address 0x7C00 now; the BIOS does so.

        ORG        0x7c00        ; Must start from here -- 0x7c00

Also, never forget we are about to develop in 16 bit mode, with 1MB memory and
16 bit registers

        BITS       16            ; still in real Mode, 16 bit

For simplifying things, we'll start by simply halting the system, in show of
perfect functionment.

        cli                      ; Clearing interrupts
        hlt                      ; Halting system

We're almost done, just remember the 512 bytes issue: the bootloader _must_ be
_exactly_ 512 bytes long
In fact, here's the tricky part: we actually count 510 instead of 512 because
the boot signature takes 2 bytes.

In the NASM interpreter, the dollar ($) operator is the address of the current
line, while the double dollar ($$) operator represents the address of the first
instruction (0x7c00).

So, $-$$ is the number of bytes from the current line to the start -- in this
case the length of the program.

        times 510 - ($-$$) db 0  ; Filling extra bytes with 0's

Finally put the boot signature, nothing less, nothing more.
The reason because it's here is simple: the BIOS needs it to chekc if the device
is bootable.
If the 511st byte contains 0xaa and the 512nd byteis 0x55, interrupt 0x19 will
load and execute the bootloader.

        dw         0xaa55        ; Boot sign, the famous aa55h


To put all the stuff in one place


;----------------------------------;
; boot.asm
;
; Intel syntax (:/)
;
; Simple bootloader
;-----------------------------------;

ORG        0x7c00        ; Must start from here 0x7c00

BITS       16            ; Still in Real Mode --> 16 bit

start:
           cli           ; Clearing interrupts
           htl           ; Halting system

           jmp     $     ; Just for the sake of putting it

times 510 - ($-$$) db 0  ; Filling extra bytes with 0's

dw         0xaa55        ; Boot signature



Now assemble with NASM

nasm -f elf -o boot.elf boot.asm

Create a floppy image

su
losetup /dev/loop0 floppy.img
mount /dev/loop0 /mnt
cp boot.elf /mnt
umount /dev/loop0
losetup -d /dev/loop0

Run bochs

su
losetup /dev/loop0 floppy.img
bochs [-f bochsrc.txt]

losetup -d /dev/loop0






The end

Reply via email to