http://giulio.hewle.com/gstuff/OS/1_Developing_a_simple_bootloader.txt1 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 |