Lesson 3. Booting the Computer (2)
In Lesson 2, you have seen that the BIOS POST routine searches for boot device and then loads in the boot sector for execution. You may wonder how the POST routine knows if a disk is a boot device or not? The secret is that to become a boot device the first sector of the disk must end with two bytes "55 AA". These two bytes in the first disk sector are the label for a boot sector. The BIOS POST routine essentially reads the first sector of a list of devices in order and checks if these two bytes exist until it finds one. If such a boot sector is found, it is loaded into memory at address 0x07C00. The boot sector is 512 bytes long and often contains a boot loader which is responsible for bringing up other boot routines or the operating system kernel.
Before introducing the boot loader implementation, let's first figure out why the BIOS loads the boot sector at 0x07C00 instead of 0x00000 or other location. It is not an arbitrarily chosen location because the BIOS allocates the 1M memory (memory range addressable in the real mode) specifically during the time of the processor initialization. Figure 1 shows the memory allocation by BIOS. The memory area from 0x07C00 to 0x07DFF is reserved for boot loader. The first 1Kb memory is used for interrupt vector, which jumps to the interrupt service routines stored in memory between 0xC0000 and 0xFFFFF. The following 128 bytes are used for BIOS data area. The 128Kb memory from 0xA0000 to 0xBFFFF is used for video memory. There are two free memory areas that you can use for your own purpose. Now you know that the boot sector can not be placed arbitrarily. Otherwise data can be overwritten, leading to corrupted execution.
The main job of boot loader is fetching the OS kernel into memory and then bringing up the OS function. Without the support of high-level OS disk routines, the boot loader has to utilize the BIOS interrupt routines to achieve disk operations. As mentioned before, this is the reason that the boot loader can not be loaded into 0x00000 since you want to use the interrupt services. The interrupt service you want to use is INT 0x13, which provides all kinds of disk operations. Before calling INT 0x13, you have to setup a list of parameters so that the interrupt service routine knows what actions to perform. Those parameters are passed through the registers as listed below:
Parameters:
AH = Function index, 0x02 means to read sectors from drive
AL = Number of sectors to read
CH = Cylinder number
CL = Sector number
DH = Head number
DL = Drive number, 0x80h means the 1st hard disk
ES:BX = Buffer address pointer
Return:
CF = Set on error, clear if no error
AH = Return code
AL = Number of actual sectors read
After handling the interrupt, those disk sectors you specified will be stored in the memory at address ES:BX. With proper configuration of the environment, you can then use a jump instruction to direct the execution to the loaded code.
In summary, the boot sector has a label of "55 AA" for the last two bytes in that sector. It utilizes the BIOS interrupt 0x13 to read in the OS kernel and prepare necessary execution environment before transferring the control to the OS.
Reference:
[1] Intel Architecture Software Developer's Manual Volume 3 - System Programming
[2] 操作系统引导探究 / Operating System Booting Investigation (Chinese)