From owner-svn-doc-head@FreeBSD.ORG Sun Jan 26 02:30:34 2014 Return-Path: Delivered-To: svn-doc-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id EA17BEF4; Sun, 26 Jan 2014 02:30:34 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id D4B021E25; Sun, 26 Jan 2014 02:30:34 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id s0Q2UYu2092496; Sun, 26 Jan 2014 02:30:34 GMT (envelope-from wblock@svn.freebsd.org) Received: (from wblock@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id s0Q2UYPh092495; Sun, 26 Jan 2014 02:30:34 GMT (envelope-from wblock@svn.freebsd.org) Message-Id: <201401260230.s0Q2UYPh092495@svn.freebsd.org> From: Warren Block Date: Sun, 26 Jan 2014 02:30:34 +0000 (UTC) To: doc-committers@freebsd.org, svn-doc-all@freebsd.org, svn-doc-head@freebsd.org Subject: svn commit: r43645 - head/en_US.ISO8859-1/books/arch-handbook/boot X-SVN-Group: doc-head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-doc-head@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for the doc tree for head List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 26 Jan 2014 02:30:35 -0000 Author: wblock Date: Sun Jan 26 02:30:34 2014 New Revision: 43645 URL: http://svnweb.freebsd.org/changeset/doc/43645 Log: Rewrite of portions of the Boot chapter by Sergio Andrés Gómez del Real. Committed version is a modified version of the one submitted with the patch. Thanks to Sergio Andrés Gómez del Real for the submission, to John-Mark Gurney for technical review, and to both for their patience. PR: docs/185780 Submitted by: Sergio Andrés Gómez del Real Reviewed by: jmg Modified: head/en_US.ISO8859-1/books/arch-handbook/boot/chapter.xml Modified: head/en_US.ISO8859-1/books/arch-handbook/boot/chapter.xml ============================================================================== --- head/en_US.ISO8859-1/books/arch-handbook/boot/chapter.xml Sun Jan 26 00:10:46 2014 (r43644) +++ head/en_US.ISO8859-1/books/arch-handbook/boot/chapter.xml Sun Jan 26 02:30:34 2014 (r43645) @@ -4,6 +4,8 @@ The FreeBSD Documentation Project Copyright (c) 2002 Sergey Lyubka All rights reserved +Copyright (c) 2014 Sergio Andr?s G?mez del Real +All rights reserved $FreeBSD$ --> @@ -25,6 +27,18 @@ $FreeBSD$ + + + + + Sergio Andrés + Gómez del Real + + + Updated and enhanced by + + + @@ -37,88 +51,103 @@ $FreeBSD$ booting system initialization This chapter is an overview of the boot and system - initialization process, starting from the BIOS (firmware) POST, - to the first user process creation. Since the initial steps of - system startup are very architecture dependent, the IA-32 - architecture is used as an example. + initialization processes, starting from the BIOS (firmware) + POST, to the first user process creation. Since the initial + steps of system startup are very architecture dependent, the + IA-32 architecture is used as an example. + + The &os; boot process can be surprisingly complex. After + control is passed from the BIOS, a considerable amount of + low-level configuration must be done before the kernel can be + loaded and executed. This setup must be done in a simple and + flexible manner, allowing the user a great deal of customization + possibilities. Overview - A computer running FreeBSD can boot by several methods, - although the most common method, booting from a harddisk where - the OS is installed, will be discussed here. The boot process - is divided into several steps: - - - BIOS POST - boot0 stage - boot2 stage - loader stage - kernel initialization - + The boot process is an extremely machine-dependent + activity. Not only must code be written for every computer + architecture, but there may also be multiple types of booting on + the same architecture. For example, looking at + /usr/sys/src/boot + reveals a great amount of architecture-dependent code. There is + a directory for each of the various supported architectures. In + the x86-specific i386 + directory, there are subdirectories for different boot standards + like mbr (Master Boot Record), + gpt (GUID Partition + Table), and efi (Extensible Firmware + Interface). Each boot standard has its own conventions and data + structures. The example that follows shows booting an x86 + computer from an MBR hard drive with the &os; + boot0 multi-boot loader stored in the very + first sector. That boot code starts the &os; three-stage boot + process. + + The key to understanding this process is that it is a series + of stages of increasing complexity. These stages are + boot1, boot2, and + loader (see &man.boot.8; for more detail). + The boot system executes each stage in sequence. The last + stage, loader, is responsible for loading + the &os; kernel. Each stage is examined in the following + sections. - BIOS POST - boot0 - boot2 - loader - The boot0 and boot2 - stages are also referred to as bootstrap stages 1 and - 2 in &man.boot.8; as the first steps in FreeBSD's - 3-stage bootstrapping procedure. Various information is printed - on the screen at each stage, so you may visually recognize them - using the table that follows. Please note that the actual data + Here is an example of the output generated by the + different boot stages. Actual output may differ from machine to machine: - Output (may vary) - BIOS (firmware) messages + &os; Component + Output (may vary) - F1 FreeBSD + boot0 + F1 FreeBSD F2 BSD -F5 Disk 2 - boot0 +F5 Disk 2 - >>FreeBSD/i386 BOOT -Default: 1:ad(1,a)/boot/loader -boot: - boot2 + boot2 This prompt will appear if the user presses a key just after selecting an OS to boot at the boot0 - stage. + stage. + >>FreeBSD/i386 BOOT +Default: 1:ad(1,a)/boot/loader +boot: - BTX loader 1.0 BTX version is 1.01 -BIOS drive A: is disk0 -BIOS drive C: is disk1 -BIOS 639kB/64512kB available memory -FreeBSD/i386 bootstrap loader, Revision 0.8 + loader + BTX loader 1.00 BTX version is 1.02 +Consoles: internal video/keyboard +BIOS drive C: is disk0 +BIOS 639kB/2096064kB available memory + +FreeBSD/x86 bootstrap loader, Revision 1.1 Console internal video/keyboard -(jkh@bento.freebsd.org, Mon Nov 20 11:41:23 GMT 2000) -/kernel text=0x1234 data=0x2345 syms=[0x4+0x3456] -Hit [Enter] to boot immediately, or any other key for command prompt -Booting [kernel] in 9 seconds..._ - loader +(root@snap.freebsd.org, Thu Jan 16 22:18:05 UTC 2014) +Loading /boot/defaults/loader.conf +/boot/kernel/kernel text=0xed9008 data=0x117d28+0x176650 syms=[0x8+0x137988+0x8+0x1515f8] - Copyright (c) 1992-2002 The FreeBSD Project. + kernel + Copyright (c) 1992-2013 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. -FreeBSD 4.6-RC #0: Sat May 4 22:49:02 GMT 2002 - devnull@kukas:/usr/obj/usr/src/sys/DEVNULL -Timecounter "i8254" frequency 1193182 Hz - kernel +FreeBSD is a registered trademark of The FreeBSD Foundation. +FreeBSD 10.0-RELEASE #0 r260789: Thu Jan 16 22:34:59 UTC 2014 + root@snap.freebsd.org:/usr/obj/usr/src/sys/GENERIC amd64 +FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610 @@ -126,84 +155,114 @@ Timecounter "i8254" frequency 1193182 H - BIOS POST + The <acronym>BIOS</acronym> - When the PC powers on, the processor's registers are set - to some predefined values. One of the registers is the + When the computer powers on, the processor's registers are + set to some predefined values. One of the registers is the instruction pointer register, and its value after a power on is well defined: it is a 32-bit value of - 0xfffffff0. The instruction pointer register points to code to - be executed by the processor. One of the registers is the + 0xfffffff0. The instruction pointer register + (also known as the Program Counter) points to code to be + executed by the processor. Another important register is the cr0 32-bit control register, and its value - just after the reboot is 0. One of the cr0's bits, the bit PE - (Protection Enabled) indicates whether the processor is running - in protected or real mode. Since at boot time this bit is - cleared, the processor boots in real mode. Real mode means, + just after a reboot is 0. One of + cr0's bits, the PE (Protection Enabled) bit, + indicates whether the processor is running in 32-bit protected + mode or 16-bit real mode. Since this bit is cleared at boot + time, the processor boots in 16-bit real mode. Real mode means, among other things, that linear and physical addresses are - identical. - - The value of 0xfffffff0 is slightly less then 4Gb, so unless - the machine has 4Gb physical memory, it cannot point to a valid - memory address. The computer's hardware translates this address - so that it points to a BIOS memory block. - - BIOS stands for Basic Input Output - System, and it is a chip on the motherboard that - has a relatively small amount of read-only memory (ROM). This + identical. The reason for the processor not to start + immediately in 32-bit protected mode is backwards compatibility. + In particular, the boot process relies on the services provided + by the BIOS, and the BIOS + itself works in legacy, 16-bit code. + + The value of 0xfffffff0 is slightly less + than 4 GB, so unless the machine has 4 GB of physical + memory, it cannot point to a valid memory address. The + computer's hardware translates this address so that it points to + a BIOS memory block. + + The BIOS (Basic Input Output + System) is a chip on the motherboard that has a relatively small + amount of read-only memory (ROM). This memory contains various low-level routines that are specific to - the hardware supplied with the motherboard. So, the processor - will first jump to the address 0xfffffff0, which really resides - in the BIOS's memory. Usually this address contains a jump - instruction to the BIOS's POST routines. - - POST stands for Power On Self Test. - This is a set of routines including the memory check, system bus - check and other low-level stuff so that the CPU can initialize - the computer properly. The important step on this stage is - determining the boot device. All modern BIOS's allow the boot - device to be set manually, so you can boot from a floppy, - CD-ROM, harddisk etc. - - The very last thing in the POST is the INT - 0x19 instruction. That instruction reads 512 bytes - from the first sector of boot device into the memory at address - 0x7c00. The term first sector originates - from harddrive architecture, where the magnetic plate is divided - to a number of cylindrical tracks. Tracks are numbered, and - every track is divided by a number (usually 64) sectors. Track - number 0 is the outermost on the magnetic plate, and sector 1, - the first sector (tracks, or, cylinders, are numbered starting - from 0, but sectors - starting from 1), has a special meaning. - It is also called Master Boot Record, or MBR. The remaining - sectors on the first track are never used Some - utilities such as &man.disklabel.8; may store the - information in this area, mostly in the second - sector.. + the hardware supplied with the motherboard. The processor will + first jump to the address 0xfffffff0, which really resides in + the BIOS's memory. Usually this address + contains a jump instruction to the BIOS's + POST routines. + + The POST (Power On Self Test) + is a set of routines including the memory check, system bus + check, and other low-level initialization so the + CPU can set up the computer properly. The + important step of this stage is determining the boot device. + Modern BIOS implementations permit the + selection of a boot device, allowing booting from a floppy, + CD-ROM, hard disk, or other devices. + + The very last thing in the POST is the + INT 0x19 instruction. The + INT 0x19 handler reads 512 bytes from the + first sector of boot device into the memory at address + 0x7c00. The term + first sector originates from hard drive + architecture, where the magnetic plate is divided into a number + of cylindrical tracks. Tracks are numbered, and every track is + divided into a number (usually 64) of sectors. Track numbers + start at 0, but sector numbers start from 1. Track 0 is the + outermost on the magnetic plate, and sector 1, the first sector, + has a special purpose. It is also called the + MBR, or Master Boot Record. The remaining + sectors on the first track are never used. + + This sector is our boot-sequence starting point. As we will + see, this sector contains a copy of our + boot0 program. A jump is made by the + BIOS to address 0x7c00 so + it starts executing. - <literal>boot0</literal> Stage + The Master Boot Record (<literal>boot0</literal>) MBR - Take a look at the file /boot/boot0. - This is a small 512-byte file, and it is exactly what FreeBSD's - installation procedure wrote to your harddisk's MBR if you chose - the bootmanager option at installation - time. + + After control is received from the BIOS + at memory address 0x7c00, + boot0 starts executing. It is the first + piece of code under &os; control. The task of + boot0 is quite simple: scan the partition + table and let the user choose which partition to boot from. The + Partition Table is a special, standard data structure embedded + in the MBR (hence embedded in + boot0) describing the four standard PC + partitions + + . + boot0 resides in the filesystem as + /boot/boot0. It is a small 512-byte file, + and it is exactly what &os;'s installation procedure wrote to + the hard disk's MBR if you chose the bootmanager + option at installation time. Indeed, + boot0 is the + MBR. As mentioned previously, the INT 0x19 - instruction loads an MBR, i.e., the boot0 - content, into the memory at address 0x7c00. Taking a look at - the file sys/boot/i386/boot0/boot0.S can - give a guess at what is happening there - this is the boot - manager, which is an awesome piece of code written by Robert - Nordier. - - The MBR, or, boot0, has a special - structure starting from offset 0x1be, called the - partition table. It has 4 records of 16 - bytes each, called partition records, which - represent how the harddisk(s) are partitioned, or, in FreeBSD's + instruction causes the INT 0x19 handler to + load an MBR (boot0) into + memory at address 0x7c00. The source file + for boot0 can be found in + sys/boot/i386/boot0/boot0.S - which is an + awesome piece of code written by Robert Nordier. + + A special structure starting from offset + 0x1be in the MBR is called + the partition table. It has four records + of 16 bytes each, called partition records, + which represent how the hard disk is partitioned, or, in &os;'s terminology, sliced. One byte of those 16 says whether a partition (slice) is bootable or not. Exactly one record must have that flag set, otherwise boot0's code @@ -229,186 +288,1471 @@ Timecounter "i8254" frequency 1193182 H - A partition record descriptor has the information about + A partition record descriptor contains information about where exactly the partition resides on the drive. Both - descriptors, LBA and CHS, describe the same information, but in - different ways: LBA (Logical Block Addressing) has the starting - sector for the partition and the partition's length, while CHS - (Cylinder Head Sector) has coordinates for the first and last - sectors of the partition. - - The boot manager scans the partition table and prints the - menu on the screen so the user can select what disk and what - slice to boot. By pressing an appropriate key, - boot0 performs the following - actions: + descriptors, LBA and CHS, + describe the same information, but in different ways: + LBA (Logical Block Addressing) has the + starting sector for the partition and the partition's length, + while CHS (Cylinder Head Sector) has + coordinates for the first and last sectors of the partition. + The partition table ends with the special signature + 0xaa55. + + The MBR must fit into 512 bytes, a single + disk sector. This program uses low-level tricks + like taking advantage of the side effects of certain + instructions and reusing register values from previous + operations to make the most out of the fewest possible + instructions. Care must also be taken when handling the + partition table, which is embedded in the MBR + itself. For these reasons, be very careful when modifying + boot0.S. + + Note that the boot0.S source file + is assembled as is: instructions are translated + one by one to binary, with no additional information (no + ELF file format, for example). This kind of + low-level control is achieved at link time through special + control flags passed to the linker. For example, the text + section of the program is set to be located at address + 0x600. In practice this means that + boot0 must be loaded to memory address + 0x600 in order to function properly. + + It is worth looking at the Makefile for + boot0 + (sys/boot/i386/boot0/Makefile), as it + defines some of the run-time behavior of + boot0. For instance, if a terminal + connected to the serial port (COM1) is used for I/O, the macro + SIO must be defined + (-DSIO). -DPXE enables + boot through PXE by pressing + F6. Additionally, the program defines a set of + flags that allow further modification of + its behavior. All of this is illustrated in the + Makefile. For example, look at the + linker directives which command the linker to start the text + section at address 0x600, and to build the + output file as is (strip out any file + formatting): + +
+ <filename>sys/boot/i386/boot0/Makefile</filename> + + BOOT_BOOT0_ORG?=0x600 + LDFLAGS=-e start -Ttext ${BOOT_BOOT0_ORG} \ + -Wl,-N,-S,--oformat,binary +
+ + Let us now start our study of the MBR, or + boot0, starting where execution + begins. + + + Some modifications have been made to some instructions in + favor of better exposition. For example, some macros are + expanded, and some macro tests are omitted when the result of + the test is known. This applies to all of the code examples + shown. + + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + start: + cld # String ops inc + xorw %ax,%ax # Zero + movw %ax,%es # Address + movw %ax,%ds # data + movw %ax,%ss # Set up + movw 0x7c00,%sp # stack +
+ + This first block of code is the entry point of the program. + It is where the BIOS transfers control. + First, it makes sure that the string operations autoincrement + its pointer operands (the cld instruction) + + When in doubt, we refer the reader to the official Intel + manuals, which describe the exact semantics for each + instruction: .. + Then, as it makes no assumption about the state of the segment + registers, it initializes them. Finally, it sets the stack + pointer register (%sp) to address + 0x7c00, so we have a working stack. + + The next block is responsible for the relocation and + subsequent jump to the relocated code. + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + movw $0x7c00,%si # Source + movw $0x600,%di # Destination + movw $512,%cx # Word count + rep # Relocate + movsb # code + movw %di,%bp # Address variables + movb $16,%cl # Words to clear + rep # Zero + stosb # them + incb -0xe(%di) # Set the S field to 1 + jmp main-0x7c00+0x600 # Jump to relocated code +
+ + Because boot0 is loaded by the + BIOS to address 0x7C00, it + copies itself to address 0x600 and then + transfers control there (recall that it was linked to execute at + address 0x600). The source address, + 0x7c00, is copied to register + %si. The destination address, + 0x600, to register %di. + The number of bytes to copy, 512 (the + program's size), is copied to register %cx. + Next, the rep instruction repeats the + instruction that follows, that is, movsb, the + number of times dictated by the %cx register. + The movsb instruction copies the byte pointed + to by %si to the address pointed to by + %di. This is repeated another 511 times. On + each repetition, both the source and destination registers, + %si and %di, are + incremented by one. Thus, upon completion of the 512-byte copy, + %di has the value + 0x600+512= + 0x800, and %si has the + value 0x7c00+512= + 0x7e00; we have thus completed the code + relocation. + + Next, the destination register + %di is copied to %bp. + %bp gets the value 0x800. + The value 16 is copied to + %cl in preparation for a new string operation + (like our previous movsb). Now, + stosb is executed 16 times. This instruction + copies a 0 value to the address pointed to by + the destination register (%di, which is + 0x800), and increments it. This is repeated + another 15 times, so %di ends up with value + 0x810. Effectively, this clears the address + range 0x800-0x80f. This + range is used as a (fake) partition table for writing the + MBR back to disk. Finally, the sector field + for the CHS addressing of this fake partition + is given the value 1 and a jump is made to the main function + from the relocated code. Note that until this jump to the + relocated code, any reference to an absolute address was + avoided. + + The following code block tests whether the drive number + provided by the BIOS should be used, or + the one stored in boot0. + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + main: + testb $SETDRV,-69(%bp) # Set drive number? + jnz disable_update # Yes + testb %dl,%dl # Drive number valid? + js save_curdrive # Possibly (0x80 set) +
+ + This code tests the SETDRV bit + (0x20) in the flags + variable. Recall that register %bp points to + address location 0x800, so the test is done + to the flags variable at address + 0x800-69= + 0x7bb. This is an example of the type of + modifications that can be done to boot0. + The SETDRV flag is not set by default, but it + can be set in the Makefile. When set, the + drive number stored in the MBR is used + instead of the one provided by the BIOS. We + assume the defaults, and that the BIOS + provided a valid drive number, so we jump to + save_curdrive. + + The next block saves the drive number provided by the + BIOS, and calls putn to + print a new line on the screen. + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + save_curdrive: + movb %dl, (%bp) # Save drive number + pushw %dx # Also in the stack +#ifdef TEST /* test code, print internal bios drive */ + rolb $1, %dl + movw $drive, %si + call putkey +#endif + callw putn # Print a newline +
+ + Note that we assume TEST is not defined, + so the conditional code in it is not assembled and will not + appear in our executable boot0. + + Our next block implements the actual scanning of the + partition table. It prints to the screen the partition type for + each of the four entries in the partition table. It compares + each type with a list of well-known operating system file + systems. Examples of recognized partition types are + NTFS (&windows;, ID 0x7), + ext2fs (&linux;, ID 0x83), and, of course, + ffs/ufs2 (&os;, ID 0xa5). + The implementation is fairly simple. + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + movw $(partbl+0x4),%bx # Partition table (+4) + xorw %dx,%dx # Item number + +read_entry: + movb %ch,-0x4(%bx) # Zero active flag (ch == 0) + btw %dx,_FLAGS(%bp) # Entry enabled? + jnc next_entry # No + movb (%bx),%al # Load type + test %al, %al # skip empty partition + jz next_entry + movw $bootable_ids,%di # Lookup tables + movb $(TLEN+1),%cl # Number of entries + repne # Locate + scasb # type + addw $(TLEN-1), %di # Adjust + movb (%di),%cl # Partition + addw %cx,%di # description + callw putx # Display it + +next_entry: + incw %dx # Next item + addb $0x10,%bl # Next entry + jnc read_entry # Till done +
+ + It is important to note that the active flag for each entry + is cleared, so after the scanning, no + partition entry is active in our memory copy of + boot0. Later, the active flag will be set + for the selected partition. This ensures that only one active + partition exists if the user chooses to write the changes back + to disk. + + The next block tests for other drives. At startup, + the BIOS writes the number of drives present + in the computer to address 0x475. If there + are any other drives present, boot0 prints + the current drive to screen. The user may command + boot0 to scan partitions on another drive + later. + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + popw %ax # Drive number + subb $0x79,%al # Does next + cmpb 0x475,%al # drive exist? (from BIOS?) + jb print_drive # Yes + decw %ax # Already drive 0? + jz print_prompt # Yes +
+ + We make the assumption that a single drive is present, so + the jump to print_drive is not performed. We + also assume nothing strange happened, so we jump to + print_prompt. + + This next block just prints out a prompt followed by the + default option: + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + print_prompt: + movw $prompt,%si # Display + callw putstr # prompt + movb _OPT(%bp),%dl # Display + decw %si # default + callw putkey # key + jmp start_input # Skip beep +
+ + Finally, a jump is performed to + start_input, where the + BIOS services are used to start a timer and + for reading user input from the keyboard; if the timer expires, + the default option will be selected: + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + start_input: + xorb %ah,%ah # BIOS: Get + int $0x1a # system time + movw %dx,%di # Ticks when + addw _TICKS(%bp),%di # timeout +read_key: + movb $0x1,%ah # BIOS: Check + int $0x16 # for keypress + jnz got_key # Have input + xorb %ah,%ah # BIOS: int 0x1a, 00 + int $0x1a # get system time + cmpw %di,%dx # Timeout? + jb read_key # No +
+ + An interrupt is requested with number + 0x1a and argument 0 in + register %ah. The BIOS + has a predefined set of services, requested by applications as + software-generated interrupts through the int + instruction and receiving arguments in registers (in this case, + %ah). Here, particularly, we are requesting + the number of clock ticks since last midnight; this value is + computed by the BIOS through the + RTC (Real Time Clock). This clock can be + programmed to work at frequencies ranging from 2 Hz to + 8192 Hz. The BIOS sets it to + 18.2 Hz at startup. When the request is satisfied, a + 32-bit result is returned by the BIOS in + registers %cx and %dx + (lower bytes in %dx). This result (the + %dx part) is copied to register + %di, and the value of the + TICKS variable is added to + %di. This variable resides in + boot0 at offset _TICKS + (a negative value) from register %bp (which, + recall, points to 0x800). The default value + of this variable is 0xb6 (182 in decimal). + Now, the idea is that boot0 constantly + requests the time from the BIOS, and when the + value returned in register %dx is greater + than the value stored in %di, the time is up + and the default selection will be made. Since the RTC ticks + 18.2 times per second, this condition will be met after 10 + seconds (this default behaviour can be changed in the + Makefile). Until this time has passed, + boot0 continually asks the + BIOS for any user input; this is done through + int 0x16, argument 1 in + %ah. + + Whether a key was pressed or the time expired, subsequent + code validates the selection. Based on the selection, the + register %si is set to point to the + appropriate partition entry in the partition table. This new + selection overrides the previous default one. Indeed, it + becomes the new default. Finally, the ACTIVE flag of the + selected partition is set. If it was enabled at compile time, + the in-memory version of boot0 with these + modified values is written back to the MBR on + disk. We leave the details of this implementation to the + reader. + + We now end our study with the last code block from the + boot0 program: + +
+ <filename>sys/boot/i386/boot0/boot0.S</filename> + + movw $0x7c00,%bx # Address for read + movb $0x2,%ah # Read sector + callw intx13 # from disk + jc beep # If error + cmpw $0xaa55,0x1fe(%bx) # Bootable? + jne beep # No + pushw %si # Save ptr to selected part. + callw putn # Leave some space + popw %si # Restore, next stage uses it + jmp *%bx # Invoke bootstrap +
+ + Recall that %si points to the selected + partition entry. This entry tells us where the partition begins + on disk. We assume, of course, that the partition selected is + actually a &os; slice. + + + From now on, we will favor the use of the technically + more accurate term slice rather than + partition. + + + The transfer buffer is set to 0x7c00 + (register %bx), and a read for the first + sector of the &os; slice is requested by calling + intx13. We assume that everything went okay, + so a jump to beep is not performed. In + particular, the new sector read must end with the magic sequence + 0xaa55. Finally, the value at + %si (the pointer to the selected partition + table) is preserved for use by the next stage, and a jump is + performed to address 0x7c00, where execution + of our next stage (the just-read block) is started. +
+ + + <literal>boot1</literal> Stage + + So far we have gone through the following sequence: - modifies the bootable flag for the selected partition to - make it bootable, and clears the previous + The BIOS did some early hardware + initialization, including the POST. The + MBR (boot0) was + loaded from absolute disk sector one to address + 0x7c00. Execution control was passed to + that location. - saves itself to disk to remember what partition (slice) - has been selected so to use it as the default on the next - boot + boot0 relocated itself to the + location it was linked to execute + (0x600), followed by a jump to continue + execution at the appropriate place. Finally, + boot0 loaded the first disk sector from + the &os; slice to address 0x7c00. + Execution control was passed to that location. + + + boot1 is the next step in the + boot-loading sequence. It is the first of three boot stages. + Note that we have been dealing exclusively + with disk sectors. Indeed, the BIOS loads + the absolute first sector, while boot0 + loads the first sector of the &os; slice. Both loads are to + address 0x7c00. We can conceptually think of + these disk sectors as containing the files + boot0 and boot1, + respectively, but in reality this is not entirely true for + boot1. Strictly speaking, unlike + boot0, boot1 is not + part of the boot blocks + + There is a file /boot/boot1, but it + is not the written to the beginning of the &os; slice. + Instead, it is concatenated with boot2 + to form boot, which + is written to the beginning of the &os; + slice and read at boot time.. + Instead, a single, full-blown file, boot + (/boot/boot), is what ultimately is + written to disk. This file is a combination of + boot1, boot2 and the + Boot Extender (or BTX). + This single file is greater in size than a single sector + (greater than 512 bytes). Fortunately, + boot1 occupies exactly + the first 512 bytes of this single file, so when + boot0 loads the first sector of the &os; + slice (512 bytes), it is actually loading + boot1 and transferring control to + it. + + The main task of boot1 is to load the + next boot stage. This next stage is somewhat more complex. It + is composed of a server called the Boot Extender, + or BTX, and a client, called + boot2. As we will see, the last boot + stage, loader, is also a client of the + BTX server. + + Let us now look in detail at what exactly is done by + boot1, starting like we did for + boot0, at its entry point: + +
+ <filename>sys/boot/i386/boot2/boot1.S</filename> + + start: + jmp main +
+ + The entry point at start simply jumps + past a special data area to the label main, + which in turn looks like this: + +
+ <filename>sys/boot/i386/boot2/boot1.S</filename> + + main: + cld # String ops inc + xor %cx,%cx # Zero + mov %cx,%es # Address + mov %cx,%ds # data + mov %cx,%ss # Set up + mov $start,%sp # stack + mov %sp,%si # Source + mov $0x700,%di # Destination + incb %ch # Word count + rep # Copy + movsw # code +
+ + Just like boot0, this + code relocates boot1, + this time to memory address 0x700. However, + unlike boot0, it does not jump there. + boot1 is linked to execute at + address 0x7c00, effectively where it was + loaded in the first place. The reason for this relocation will + be discussed shortly. + + Next comes a loop that looks for the &os; slice. Although + boot0 loaded boot1 + from the &os; slice, no information was passed to it about this + + Actually we did pass a pointer to the slice entry in + register %si. However, + boot1 does not assume that it was + loaded by boot0 (perhaps some other + MBR loaded it, and did not pass this + information), so it assumes nothing., + so boot1 must rescan the + partition table to find where the &os; slice starts. Therefore + it rereads the MBR: + +
+ <filename>sys/boot/i386/boot2/boot1.S</filename> + + mov $part4,%si # Partition + cmpb $0x80,%dl # Hard drive? + jb main.4 # No + movb $0x1,%dh # Block count + callw nread # Read MBR +
+ + In the code above, register %dl + maintains information about the boot device. This is passed on + by the BIOS and preserved by the + MBR. Numbers 0x80 and + greater tells us that we are dealing with a hard drive, so a + call is made to nread, where the + MBR is read. Arguments to + nread are passed through + %si and %dh. The memory + address at label part4 is copied to + %si. This memory address holds a + fake partition to be used by + nread. The following is the data in the fake + partition: + +
+ <filename>sys/boot/i386/boot2/Makefile</filename> + + part4: + .byte 0x80, 0x00, 0x01, 0x00 + .byte 0xa5, 0xfe, 0xff, 0xff + .byte 0x00, 0x00, 0x00, 0x00 + .byte 0x50, 0xc3, 0x00, 0x00 +
+ + In particular, the LBA for this fake + partition is hardcoded to zero. This is used as an argument to + the BIOS for reading absolute sector one from + the hard drive. Alternatively, CHS addressing could be used. + In this case, the fake partition holds cylinder 0, head 0 and + sector 1, which is equivalent to absolute sector one. + + Let us now proceed to take a look at + nread: + +
+ <filename>sys/boot/i386/boot2/boot1.S</filename> + + nread: + mov $0x8c00,%bx # Transfer buffer + mov 0x8(%si),%ax # Get + mov 0xa(%si),%cx # LBA + push %cs # Read from + callw xread.1 # disk + jnc return # If success, return +
+ + Recall that %si points to the fake + partition. The word + + In the context of 16-bit real mode, a word is 2 + bytes. + at offset 0x8 is copied to register + %ax and word at offset 0xa + to %cx. They are interpreted by the + BIOS as the lower 4-byte value denoting the + LBA to be read (the upper four bytes are assumed to be zero). + Register %bx holds the memory address where + the MBR will be loaded. The instruction + pushing %cs onto the stack is very + interesting. In this context, it accomplishes nothing. However, as + we will see shortly, boot2, in conjunction + with the BTX server, also uses + xread.1. This mechanism will be discussed in + the next section. + + The code at xread.1 further calls *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***