Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-doc
Path: blob/main/documentation/content/en/books/arch-handbook/boot/_index.po
18098 views
# SOME DESCRIPTIVE TITLE
# Copyright (C) YEAR The FreeBSD Project
# This file is distributed under the same license as the FreeBSD Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: FreeBSD Documentation VERSION\n"
"POT-Creation-Date: 2025-11-08 16:17+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#. type: Title =
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:14
#, no-wrap
msgid "Bootstrapping and Kernel Initialization"
msgstr ""

#. type: YAML Front Matter: title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1
#, no-wrap
msgid "Chapter 1. Bootstrapping and Kernel Initialization"
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:52
#, no-wrap
msgid "Synopsis"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:57
msgid ""
"This chapter is an overview of the boot and system 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.  But the AMD64 and ARM64 "
"architectures are much more important and compelling examples and should be "
"explained in the near future according to the topic of this document."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:61
msgid ""
"The FreeBSD 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."
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:63
#, no-wrap
msgid "Overview"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:76
msgid ""
"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, a "
"directory listing of [.filename]#stand# reveals a great amount of "
"architecture-dependent code.  There is a directory for each of the various "
"supported architectures.  FreeBSD supports the CSM boot standard "
"(Compatibility Support Module).  So CSM is supported (with both GPT and MBR "
"partitioning support) and UEFI booting (GPT is totally supported, MBR is "
"mostly supported).  It also supports loading files from ext2fs, MSDOS, UFS "
"and ZFS.  FreeBSD also supports the boot environment feature of ZFS which "
"allows the HOST OS to communicate details about what to boot that go beyond "
"a simple partition as was possible in the past.  But UEFI is more relevant "
"than the CSM these days.  The example that follows shows booting an x86 "
"computer from an MBR-partitioned hard drive with the FreeBSD "
"[.filename]#boot0# multi-boot loader stored in the very first sector.  That "
"boot code starts the FreeBSD three-stage boot process."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:82
msgid ""
"The key to understanding this process is that it is a series of stages of "
"increasing complexity.  These stages are [.filename]#boot1#, "
"[.filename]#boot2#, and [.filename]#loader# (see man:boot[8] for more "
"detail).  The boot system executes each stage in sequence.  The last stage, "
"[.filename]#loader#, is responsible for loading the FreeBSD kernel.  Each "
"stage is examined in the following sections."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:85
msgid ""
"Here is an example of the output generated by the different boot stages.  "
"Actual output may differ from machine to machine:"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:91
#, no-wrap
msgid "*FreeBSD Component*"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:93
#, no-wrap
msgid "*Output (may vary)*"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:94
#, no-wrap
msgid "`boot0`"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:103
#, no-wrap
msgid ""
"[source,bash]\n"
"....\n"
"F1    FreeBSD\n"
"F2    BSD\n"
"F5    Disk 2\n"
"...."
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:104
#, no-wrap
msgid "`boot2` footnote:[This prompt will appear if the user presses a key just after selecting an OS to boot at the boot0 stage.]"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:113
#, no-wrap
msgid ""
"[source,bash]\n"
"....\n"
">>FreeBSD/x86 BOOT\n"
"Default: 0:ad(0p4)/boot/loader\n"
"boot:\n"
"...."
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:114
#, no-wrap
msgid "[.filename]#loader#"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:130
#, no-wrap
msgid ""
"[source,bash]\n"
"....\n"
"BTX loader 1.00 BTX version is 1.02\n"
"Consoles: internal video/keyboard\n"
"BIOS drive C: is disk0\n"
"BIOS 639kB/2096064kB available memory\n"
"\n"
"FreeBSD/x86 bootstrap loader, Revision 1.1\n"
"Console internal video/keyboard\n"
"([email protected], Fri Apr  9 04:04:45 UTC 2021)\n"
"Loading /boot/defaults/loader.conf\n"
"/boot/kernel/kernel text=0xed9008 data=0x117d28+0x176650 syms=[0x8+0x137988+0x8+0x1515f8]\n"
"...."
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:131
#, no-wrap
msgid "kernel"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:144
#, no-wrap
msgid ""
"[source,bash]\n"
"....\n"
"Copyright (c) 1992-2021 The FreeBSD Project.\n"
"Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994\n"
"        The Regents of the University of California. All rights reserved.\n"
"FreeBSD is a registered trademark of The FreeBSD Foundation.\n"
"FreeBSD 13.0-RELEASE 0 releng/13.0-n244733-ea31abc261f: Fri Apr  9 04:04:45 UTC 2021\n"
"    [email protected]:/usr/obj/usr/src/i386.i386/sys/GENERIC i386\n"
"FreeBSD clang version 11.0.1 ([email protected]:llvm/llvm-project.git llvmorg-11.0.1-0-g43ff75f2c3fe)\n"
"...."
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:147
#, no-wrap
msgid "The BIOS"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:158
msgid ""
"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 (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 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 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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:161
msgid ""
"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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:166
msgid ""
"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.  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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:170
msgid ""
"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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:179
msgid ""
"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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:183
msgid ""
"This sector is our boot-sequence starting point.  As we will see, this "
"sector contains a copy of our [.filename]#boot0# program.  A jump is made by "
"the BIOS to address `0x7c00` so it starts executing."
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:185
#, no-wrap
msgid "The Master Boot Record (`boot0`)"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:194
msgid ""
"After control is received from the BIOS at memory address `0x7c00`, "
"[.filename]#boot0# starts executing.  It is the first piece of code under "
"FreeBSD control.  The task of [.filename]#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 [.filename]#boot0#) describing the four standard PC "
"\"partitions\".  [.filename]#boot0# resides in the filesystem as "
"[.filename]#/boot/boot0#.  It is a small 512-byte file, and it is exactly "
"what FreeBSD's installation procedure wrote to the hard disk's MBR if you "
"chose the \"bootmanager\" option at installation time.  Indeed, "
"[.filename]#boot0# _is_ the MBR."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:197
msgid ""
"As mentioned previously, we're calling the BIOS `INT 0x19` to load the MBR "
"([.filename]#boot0#) into memory at address `0x7c00`.  The source file for "
"[.filename]#boot0# can be found in [.filename]#stand/i386/boot0/boot0.S# - "
"which is an awesome piece of code written by Robert Nordier."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:202
msgid ""
"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 FreeBSD'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 "
"[.filename]#boot0#'s code will refuse to proceed."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:204
msgid "A partition record has the following fields:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:206
msgid "the 1-byte filesystem type"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:207
msgid "the 1-byte bootable flag"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:208
msgid "the 6 byte descriptor in CHS format"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:209
msgid "the 8 byte descriptor in LBA format"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:213
msgid ""
"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 partition table ends with the special signature `0xaa55`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:218
msgid ""
"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 [.filename]#boot0.S#."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:223
msgid ""
"Note that the [.filename]#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 [.filename]#boot0# must be "
"loaded to memory address `0x600` in order to function properly."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:230
msgid ""
"It is worth looking at the [.filename]#Makefile# for [.filename]#boot0# "
"([.filename]#stand/i386/boot0/Makefile#), as it defines some of the run-time "
"behavior of [.filename]#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 kbd:[F6].  "
"Additionally, the program defines a set of _flags_ that allow further "
"modification of its behavior.  All of this is illustrated in the "
"[.filename]#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):"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:235
#, no-wrap
msgid ""
"      BOOT_BOOT0_ORG?=0x600\n"
"      ORG=${BOOT_BOOT0_ORG}\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:237
#, no-wrap
msgid "[.filename]#stand/i386/boot0/Makefile# [[boot-boot0-makefile-as-is]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:239
msgid ""
"Let us now start our study of the MBR, or [.filename]#boot0#, starting where "
"execution begins."
msgstr ""

#. type: delimited block = 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:245
msgid ""
"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."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:256
#, no-wrap
msgid ""
"start:\n"
"      cld\t\t\t# String ops inc\n"
"      xorw %ax,%ax\t\t# Zero\n"
"      movw %ax,%es\t\t# Address\n"
"      movw %ax,%ds\t\t#  data\n"
"      movw %ax,%ss\t\t# Set up\n"
"      movw $LOAD,%sp\t\t#  stack\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:258
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-entrypoint]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:264
msgid ""
"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) footnote:[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 ($LOAD = address `0x7c00`), so we "
"have a working stack."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:266
msgid ""
"The next block is responsible for the relocation and subsequent jump to the "
"relocated code."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:280
#, no-wrap
msgid ""
"      movw %sp,%si     # Source\n"
"      movw $start,%di\t\t# Destination\n"
"      movw $0x100,%cx\t\t# Word count\n"
"      rep\t\t\t# Relocate\n"
"      movsw\t\t\t#  code\n"
"      movw %di,%bp\t\t# Address variables\n"
"      movb $0x8,%cl\t\t# Words to clear\n"
"      rep\t\t\t# Zero\n"
"      stosw\t\t\t#  them\n"
"      incb -0xe(%di)\t\t# Set the S field to 1\n"
"      jmp main-LOAD+ORIGIN\t# Jump to relocated code\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:282
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-relocation]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:293
msgid ""
"As [.filename]#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 words to copy, `256` (the program's size = 512 bytes), "
"is copied to register `%cx`.  Next, the `rep` instruction repeats the "
"instruction that follows, that is, `movsw`, the number of times dictated by "
"the `%cx` register.  The `movsw` instruction copies the word pointed to by "
"`%si` to the address pointed to by `%di`.  This is repeated another 255 "
"times.  On each repetition, both the source and destination registers, `%si` "
"and `%di`, are incremented by one.  Thus, upon completion of the 256-word "
"(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_.  Since the last update of this document, the copy instructions "
"have changed in the code, so instead of the movsb and stosb, movsw and stosw "
"have been introduced, which copy 2 bytes(1 word) in one iteration."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:304
msgid ""
"Next, the destination register `%di` is copied to `%bp`.  `%bp` gets the "
"value `0x800`.  The value `8` is copied to `%cl` in preparation for a new "
"string operation (like our previous `movsw`).  Now, `stosw` is executed 8 "
"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 7 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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:306
msgid ""
"The following code block tests whether the drive number provided by the BIOS "
"should be used, or the one stored in [.filename]#boot0#."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:318
#, no-wrap
msgid ""
"main:\n"
"      testb $SETDRV,_FLAGS(%bp)\t# Set drive number?\n"
"#ifndef CHECK_DRIVE\t/* disable drive checks */\n"
"      jz save_curdrive\t\t# no, use the default\n"
"#else\n"
"      jnz disable_update\t# Yes\n"
"      testb %dl,%dl\t\t# Drive number valid?\n"
"      js save_curdrive\t\t# Possibly (0x80 set)\n"
"#endif\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:320
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-drivenumber]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:327
msgid ""
"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 "
"[.filename]#boot0#.  The `SETDRV` flag is not set by default, but it can be "
"set in the [.filename]#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`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:329
msgid ""
"The next block saves the drive number provided by the BIOS, and calls `putn` "
"to print a new line on the screen."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:341
#, no-wrap
msgid ""
"save_curdrive:\n"
"      movb %dl, (%bp)\t\t# Save drive number\n"
"      pushw %dx\t\t\t# Also in the stack\n"
"#ifdef\tTEST\t/* test code, print internal bios drive */\n"
"      rolb $1, %dl\n"
"      movw $drive, %si\n"
"      call putkey\n"
"#endif\n"
"      callw putn\t\t# Print a newline\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:343
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-savedrivenumber]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:345
msgid ""
"Note that we assume `TEST` is not defined, so the conditional code in it is "
"not assembled and will not appear in our executable [.filename]#boot0#."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:351
msgid ""
"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(R), ID 0x7), `ext2fs` (Linux(R), ID 0x83), and, of course, `ffs`/"
"`ufs2` (FreeBSD, ID 0xa5).  The implementation is fairly simple."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:356
#, no-wrap
msgid ""
"      movw $(partbl+0x4),%bx\t# Partition table (+4)\n"
"      xorw %dx,%dx\t\t# Item number\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:372
#, no-wrap
msgid ""
"read_entry:\n"
"      movb %ch,-0x4(%bx)\t# Zero active flag (ch == 0)\n"
"      btw %dx,_FLAGS(%bp)\t# Entry enabled?\n"
"      jnc next_entry\t\t# No\n"
"      movb (%bx),%al\t\t# Load type\n"
"      test %al, %al\t\t# skip empty partition\n"
"      jz next_entry\n"
"      movw $bootable_ids,%di\t# Lookup tables\n"
"      movb $(TLEN+1),%cl\t# Number of entries\n"
"      repne\t\t\t# Locate\n"
"      scasb\t\t\t#  type\n"
"      addw $(TLEN-1), %di\t# Adjust\n"
"      movb (%di),%cl\t\t# Partition\n"
"      addw %cx,%di\t\t#  description\n"
"      callw putx\t\t# Display it\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:377
#, no-wrap
msgid ""
"next_entry:\n"
"      incw %dx\t\t\t# Next item\n"
"      addb $0x10,%bl\t\t# Next entry\n"
"      jnc read_entry\t\t# Till done\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:379
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-partition-scan]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:383
msgid ""
"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 "
"[.filename]#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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:388
msgid ""
"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, [.filename]#boot0# prints the current drive to "
"screen.  The user may command [.filename]#boot0# to scan partitions on "
"another drive later."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:397
#, no-wrap
msgid ""
"      popw %ax\t\t\t# Drive number\n"
"      subb $0x80-0x1,%al\t\t# Does next\n"
"      cmpb NHRDRV,%al\t\t#  drive exist? (from BIOS?)\n"
"      jb print_drive\t\t# Yes\n"
"      decw %ax\t\t\t# Already drive 0?\n"
"      jz print_prompt\t\t# Yes\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:399
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-test-drives]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:402
msgid ""
"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`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:404
msgid ""
"This next block just prints out a prompt followed by the default option:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:414
#, no-wrap
msgid ""
"print_prompt:\n"
"      movw $prompt,%si\t\t# Display\n"
"      callw putstr\t\t#  prompt\n"
"      movb _OPT(%bp),%dl\t# Display\n"
"      decw %si\t\t\t#  default\n"
"      callw putkey\t\t#  key\n"
"      jmp start_input\t\t# Skip beep\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:416
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-prompt]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:418
msgid ""
"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:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:434
#, no-wrap
msgid ""
"start_input:\n"
"      xorb %ah,%ah\t\t# BIOS: Get\n"
"      int $0x1a\t\t\t#  system time\n"
"      movw %dx,%di\t\t# Ticks when\n"
"      addw _TICKS(%bp),%di\t#  timeout\n"
"read_key:\n"
"      movb $0x1,%ah\t\t# BIOS: Check\n"
"      int $0x16\t\t\t#  for keypress\n"
"      jnz got_key\t\t# Have input\n"
"      xorb %ah,%ah\t\t# BIOS: int 0x1a, 00\n"
"      int $0x1a\t\t\t#  get system time\n"
"      cmpw %di,%dx\t\t# Timeout?\n"
"      jb read_key\t\t# No\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:436
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-start-input]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:449
msgid ""
"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 "
"[.filename]#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 [.filename]#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 behavior "
"can be changed in the [.filename]#Makefile#).  Until this time has passed, "
"[.filename]#boot0# continually asks the BIOS for any user input; this is "
"done through `int 0x16`, argument `1` in `%ah`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:457
msgid ""
"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 [.filename]#boot0# with "
"these modified values is written back to the MBR on disk.  We leave the "
"details of this implementation to the reader."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:459
msgid ""
"We now end our study with the last code block from the [.filename]#boot0# "
"program:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:472
#, no-wrap
msgid ""
"      movw $LOAD,%bx\t\t# Address for read\n"
"      movb $0x2,%ah\t\t# Read sector\n"
"      callw intx13\t\t#  from disk\n"
"      jc beep\t\t\t# If error\n"
"      cmpw $MAGIC,0x1fe(%bx)\t# Bootable?\n"
"      jne beep\t\t\t# No\n"
"      pushw %si\t\t\t# Save ptr to selected part.\n"
"      callw putn\t\t# Leave some space\n"
"      popw %si\t\t\t# Restore, next stage uses it\n"
"      jmp *%bx\t\t\t# Invoke bootstrap\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:474
#, no-wrap
msgid "[.filename]#stand/i386/boot0/boot0.S# [[boot-boot0-check-bootable]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:478
msgid ""
"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 FreeBSD slice."
msgstr ""

#. type: delimited block = 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:482
msgid ""
"From now on, we will favor the use of the technically more accurate term "
"\"slice\" rather than \"partition\"."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:488
msgid ""
"The transfer buffer is set to `0x7c00` (register `%bx`), and a read for the "
"first sector of the FreeBSD 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."
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:490
#, no-wrap
msgid "`boot1` Stage"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:493
msgid "So far we have gone through the following sequence:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:497
msgid ""
"The BIOS did some early hardware initialization, including the POST.  The "
"MBR ([.filename]#boot0#) was loaded from absolute disk sector one to address "
"`0x7c00`.  Execution control was passed to that location."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:500
msgid ""
"[.filename]#boot0# relocated itself to the location it was linked to execute "
"(`0x600`), followed by a jump to continue execution at the appropriate "
"place.  Finally, [.filename]#boot0# loaded the first disk sector from the "
"FreeBSD slice to address `0x7c00`.  Execution control was passed to that "
"location."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:513
msgid ""
"[.filename]#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 "
"[.filename]#boot0# loads the first sector of the FreeBSD slice.  Both loads "
"are to address `0x7c00`.  We can conceptually think of these disk sectors as "
"containing the files [.filename]#boot0# and [.filename]#boot1#, "
"respectively, but in reality this is not entirely true for "
"[.filename]#boot1#.  Strictly speaking, unlike [.filename]#boot0#, "
"[.filename]#boot1# is not part of the boot blocks footnote:[There is a file /"
"boot/boot1, but it is not the written to the beginning of the FreeBSD "
"slice.  Instead, it is concatenated with boot2 to form boot, which is "
"written to the beginning of the FreeBSD slice and read at boot time.].  "
"Instead, a single, full-blown file, [.filename]#boot# ([.filename]#/boot/"
"boot#), is what ultimately is written to disk.  This file is a combination "
"of [.filename]#boot1#, [.filename]#boot2# and the `Boot Extender` (or BTX).  "
"This single file is greater in size than a single sector (greater than 512 "
"bytes).  Fortunately, [.filename]#boot1# occupies _exactly_ the first 512 "
"bytes of this single file, so when [.filename]#boot0# loads the first sector "
"of the FreeBSD slice (512 bytes), it is actually loading [.filename]#boot1# "
"and transferring control to it."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:518
msgid ""
"The main task of [.filename]#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 [.filename]#boot2#.  As we "
"will see, the last boot stage, [.filename]#loader#, is also a client of the "
"BTX server."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:520
msgid ""
"Let us now look in detail at what exactly is done by [.filename]#boot1#, "
"starting like we did for [.filename]#boot0#, at its entry point:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:525
#, no-wrap
msgid ""
"start:\n"
"\tjmp main\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:527
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-entry]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:529
msgid ""
"The entry point at `start` simply jumps past a special data area to the "
"label `main`, which in turn looks like this:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:544
#, no-wrap
msgid ""
"main:\n"
"      cld\t\t\t# String ops inc\n"
"      xor %cx,%cx\t\t# Zero\n"
"      mov %cx,%es\t\t# Address\n"
"      mov %cx,%ds\t\t#  data\n"
"      mov %cx,%ss\t\t# Set up\n"
"      mov $start,%sp\t\t#  stack\n"
"      mov %sp,%si\t\t# Source\n"
"      mov $MEM_REL,%di\t\t# Destination\n"
"      incb %ch\t\t\t# Word count\n"
"      rep\t\t\t# Copy\n"
"      movsw\t\t\t#  code\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:546
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-main]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:551
msgid ""
"Just like [.filename]#boot0#, this code relocates [.filename]#boot1#, this "
"time to memory address `0x700`.  However, unlike [.filename]#boot0#, it does "
"not jump there.  [.filename]#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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:556
msgid ""
"Next comes a loop that looks for the FreeBSD slice.  Although "
"[.filename]#boot0# loaded [.filename]#boot1# from the FreeBSD slice, no "
"information was passed to it about this footnote:[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 [.filename]#boot1# must "
"rescan the partition table to find where the FreeBSD slice starts.  "
"Therefore it rereads the MBR:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:564
#, no-wrap
msgid ""
"      mov $part4,%si\t\t# Partition\n"
"      cmpb $0x80,%dl\t\t# Hard drive?\n"
"      jb main.4\t\t\t# No\n"
"      movb $0x1,%dh\t\t# Block count\n"
"      callw nread\t\t# Read MBR\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:566
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-find-freebsd]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:574
msgid ""
"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:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:582
#, no-wrap
msgid ""
"      part4:\n"
"\t.byte 0x80, 0x00, 0x01, 0x00\n"
"\t.byte 0xa5, 0xfe, 0xff, 0xff\n"
"\t.byte 0x00, 0x00, 0x00, 0x00\n"
"\t.byte 0x50, 0xc3, 0x00, 0x00\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:584
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot2-make-fake-partition]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:589
msgid ""
"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."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:591
msgid "Let us now proceed to take a look at `nread`:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:601
#, no-wrap
msgid ""
"nread:\n"
"      mov $MEM_BUF,%bx\t\t# Transfer buffer\n"
"      mov 0x8(%si),%ax\t\t# Get\n"
"      mov 0xa(%si),%cx\t\t#  LBA\n"
"      push %cs\t\t\t# Read from\n"
"      callw xread.1\t\t#  disk\n"
"      jnc return\t\t# If success, return\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:603
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-nread]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:612
msgid ""
"Recall that `%si` points to the fake partition.  The word footnote:[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, [.filename]#boot2#, in conjunction with the BTX server, "
"also uses `xread.1`.  This mechanism will be discussed in the next section."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:614
msgid ""
"The code at `xread.1` further calls the `read` function, which actually "
"calls the BIOS asking for the disk sector:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:631
#, no-wrap
msgid ""
"xread.1:\n"
"\tpushl $0x0\t\t#  absolute\n"
"\tpush %cx\t\t#  block\n"
"\tpush %ax\t\t#  number\n"
"\tpush %es\t\t# Address of\n"
"\tpush %bx\t\t#  transfer buffer\n"
"\txor %ax,%ax\t\t# Number of\n"
"\tmovb %dh,%al\t\t#  blocks to\n"
"\tpush %ax\t\t#  transfer\n"
"\tpush $0x10\t\t# Size of packet\n"
"\tmov %sp,%bp\t\t# Packet pointer\n"
"\tcallw read\t\t# Read from disk\n"
"\tlea 0x10(%bp),%sp\t# Clear stack\n"
"\tlret\t\t\t# To far caller\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:633
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-xread1]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:637
msgid ""
"Note the long return instruction at the end of this block.  This instruction "
"pops out the `%cs` register pushed by `nread`, and returns.  Finally, "
"`nread` also returns."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:639
msgid ""
"With the MBR loaded to memory, the actual loop for searching the FreeBSD "
"slice begins:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:659
#, no-wrap
msgid ""
"\tmov $0x1,%cx\t\t # Two passes\n"
"main.1:\n"
"\tmov $MEM_BUF+PRT_OFF,%si # Partition table\n"
"\tmovb $0x1,%dh\t\t # Partition\n"
"main.2:\n"
"\tcmpb $PRT_BSD,0x4(%si)\t # Our partition type?\n"
"\tjne main.3\t\t # No\n"
"\tjcxz main.5\t\t # If second pass\n"
"\ttestb $0x80,(%si)\t # Active?\n"
"\tjnz main.5\t\t # Yes\n"
"main.3:\n"
"\tadd $0x10,%si\t\t # Next entry\n"
"\tincb %dh\t\t # Partition\n"
"\tcmpb $0x1+PRT_NUM,%dh\t\t # In table?\n"
"\tjb main.2\t\t # Yes\n"
"\tdec %cx\t\t\t # Do two\n"
"\tjcxz main.1\t\t #  passes\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:661
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-find-part]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:665
msgid ""
"If a FreeBSD slice is identified, execution continues at `main.5`.  Note "
"that when a FreeBSD slice is found `%si` points to the appropriate entry in "
"the partition table, and `%dh` holds the partition number.  We assume that a "
"FreeBSD slice is found, so we continue execution at `main.5`:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:680
#, no-wrap
msgid ""
"main.5:\n"
"\tmov %dx,MEM_ARG\t\t\t   # Save args\n"
"\tmovb $NSECT,%dh\t\t\t   # Sector count\n"
"\tcallw nread\t\t\t   # Read disk\n"
"\tmov $MEM_BTX,%bx\t\t\t   # BTX\n"
"\tmov 0xa(%bx),%si\t\t   # Get BTX length and set\n"
"\tadd %bx,%si\t\t\t   #  %si to start of boot2.bin\n"
"\tmov $MEM_USR+SIZ_PAG*2,%di\t\t\t   # Client page 2\n"
"\tmov $MEM_BTX+(NSECT-1)*SIZ_SEC,%cx\t\t\t   # Byte\n"
"\tsub %si,%cx\t\t\t   #  count\n"
"\trep\t\t\t\t   # Relocate\n"
"\tmovsb\t\t\t\t   #  client\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:682
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-main5]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:688
msgid ""
"Recall that at this point, register `%si` points to the FreeBSD slice entry "
"in the MBR partition table, so a call to `nread` will effectively read "
"sectors at the beginning of this partition.  The argument passed on register "
"`%dh` tells `nread` to read 16 disk sectors.  Recall that the first 512 "
"bytes, or the first sector of the FreeBSD slice, coincides with the "
"[.filename]#boot1# program.  Also recall that the file written to the "
"beginning of the FreeBSD slice is not [.filename]#/boot/boot1#, but "
"[.filename]#/boot/boot#.  Let us look at the size of these files in the "
"filesystem:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:695
#, no-wrap
msgid ""
"-r--r--r--  1 root  wheel   512B Jan  8 00:15 /boot/boot0\n"
"-r--r--r--  1 root  wheel   512B Jan  8 00:15 /boot/boot1\n"
"-r--r--r--  1 root  wheel   7.5K Jan  8 00:15 /boot/boot2\n"
"-r--r--r--  1 root  wheel   8.0K Jan  8 00:15 /boot/boot\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:703
msgid ""
"Both [.filename]#boot0# and [.filename]#boot1# are 512 bytes each, so they "
"fit _exactly_ in one disk sector.  [.filename]#boot2# is much bigger, "
"holding both the BTX server and the [.filename]#boot2# client.  Finally, a "
"file called simply [.filename]#boot# is 512 bytes larger than "
"[.filename]#boot2#.  This file is a concatenation of [.filename]#boot1# and "
"[.filename]#boot2#.  As already noted, [.filename]#boot0# is the file "
"written to the absolute first disk sector (the MBR), and [.filename]#boot# "
"is the file written to the first sector of the FreeBSD slice; "
"[.filename]#boot1# and [.filename]#boot2# are _not_ written to disk.  The "
"command used to concatenate [.filename]#boot1# and [.filename]#boot2# into a "
"single [.filename]#boot# is merely `cat boot1 boot2 > boot`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:707
msgid ""
"So [.filename]#boot1# occupies exactly the first 512 bytes of "
"[.filename]#boot# and, because [.filename]#boot# is written to the first "
"sector of the FreeBSD slice, [.filename]#boot1# fits exactly in this first "
"sector.  When `nread` reads the first 16 sectors of the FreeBSD slice, it "
"effectively reads the entire [.filename]#boot# file footnote:[512*16=8192 "
"bytes, exactly the size of boot].  We will see more details about how "
"[.filename]#boot# is formed from [.filename]#boot1# and [.filename]#boot2# "
"in the next section."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:713
msgid ""
"Recall that `nread` uses memory address `0x8c00` as the transfer buffer to "
"hold the sectors read.  This address is conveniently chosen.  Indeed, "
"because [.filename]#boot1# belongs to the first 512 bytes, it ends up in the "
"address range `0x8c00`-`0x8dff`.  The 512 bytes that follows (range `0x8e00`-"
"`0x8fff`) is used to store the _bsdlabel_ footnote:[Historically known as "
"disklabel.  If you ever wondered where FreeBSD stored this information, it "
"is in this region - see man:bsdlabel[8]]."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:721
msgid ""
"Starting at address `0x9000` is the beginning of the BTX server, and "
"immediately following is the [.filename]#boot2# client.  The BTX server acts "
"as a kernel, and executes in protected mode in the most privileged level.  "
"In contrast, the BTX clients ([.filename]#boot2#, for example), execute in "
"user mode.  We will see how this is accomplished in the next section.  The "
"code after the call to `nread` locates the beginning of [.filename]#boot2# "
"in the memory buffer, and copies it to memory address `0xc000`.  This is "
"because the BTX server arranges [.filename]#boot2# to execute in a segment "
"starting at `0xa000`.  We explore this in detail in the following section."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:724
msgid ""
"The last code block of [.filename]#boot1# enables access to memory above 1MB "
"footnote:[This is necessary for legacy reasons.] and concludes with a jump "
"to the starting point of the BTX server:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:732
#, no-wrap
msgid ""
"seta20:\n"
"\tcli\t\t\t# Disable interrupts\n"
"seta20.1:\n"
"\tdec %cx\t\t\t# Timeout?\n"
"\tjz seta20.3\t\t# Yes\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:747
#, no-wrap
msgid ""
"\tinb $0x64,%al\t\t# Get status\n"
"\ttestb $0x2,%al\t\t# Busy?\n"
"\tjnz seta20.1\t\t# Yes\n"
"\tmovb $0xd1,%al\t\t# Command: Write\n"
"\toutb %al,$0x64\t\t#  output port\n"
"seta20.2:\n"
"\tinb $0x64,%al\t\t# Get status\n"
"\ttestb $0x2,%al\t\t# Busy?\n"
"\tjnz seta20.2\t\t# Yes\n"
"\tmovb $0xdf,%al\t\t# Enable\n"
"\toutb %al,$0x60\t\t#  A20\n"
"seta20.3:\n"
"\tsti\t\t\t# Enable interrupts\n"
"\tjmp 0x9010\t\t# Start BTX\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:749
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot1.S# [[boot-boot1-seta20]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:751
msgid "Note that right before the jump, interrupts are enabled."
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:753
#, no-wrap
msgid "The BTX Server"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:757
msgid ""
"Next in our boot sequence is the BTX Server.  Let us quickly remember how we "
"got here:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:759
msgid ""
"The BIOS loads the absolute sector one (the MBR, or [.filename]#boot0#), to "
"address `0x7c00` and jumps there."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:761
msgid ""
"[.filename]#boot0# relocates itself to `0x600`, the address it was linked to "
"execute, and jumps over there.  It then reads the first sector of the "
"FreeBSD slice (which consists of [.filename]#boot1#) into address `0x7c00` "
"and jumps over there."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:766
msgid ""
"[.filename]#boot1# loads the first 16 sectors of the FreeBSD slice into "
"address `0x8c00`.  This 16 sectors, or 8192 bytes, is the whole file "
"[.filename]#boot#.  The file is a concatenation of [.filename]#boot1# and "
"[.filename]#boot2#.  [.filename]#boot2#, in turn, contains the BTX server "
"and the [.filename]#boot2# client.  Finally, a jump is made to address "
"`0x9010`, the entry point of the BTX server."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:770
msgid ""
"Before studying the BTX Server in detail, let us further review how the "
"single, all-in-one [.filename]#boot# file is created.  The way "
"[.filename]#boot# is built is defined in its [.filename]#Makefile# "
"([.filename]#stand/i386/boot2/Makefile#).  Let us look at the rule that "
"creates the [.filename]#boot# file:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:775
#, no-wrap
msgid ""
"      boot: boot1 boot2\n"
"\tcat boot1 boot2 > boot\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:777
#, no-wrap
msgid "[.filename]#stand/i386/boot2/Makefile# [[boot-boot1-make-boot]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:780
msgid ""
"This tells us that [.filename]#boot1# and [.filename]#boot2# are needed, and "
"the rule simply concatenates them to produce a single file called "
"[.filename]#boot#.  The rules for creating [.filename]#boot1# are also quite "
"simple:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:785
#, no-wrap
msgid ""
"      boot1: boot1.out\n"
"\t${OBJCOPY} -S -O binary boot1.out ${.TARGET}\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:788
#, no-wrap
msgid ""
"      boot1.out: boot1.o\n"
"\t${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} boot1.o\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:790
#, no-wrap
msgid "[.filename]#stand/i386/boot2/Makefile# [[boot-boot1-make-boot1]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:799
msgid ""
"To apply the rule for creating [.filename]#boot1#, [.filename]#boot1.out# "
"must be resolved.  This, in turn, depends on the existence of "
"[.filename]#boot1.o#.  This last file is simply the result of assembling our "
"familiar [.filename]#boot1.S#, without linking.  Now, the rule for creating "
"[.filename]#boot1.out# is applied.  This tells us that [.filename]#boot1.o# "
"should be linked with `start` as its entry point, and starting at address "
"`0x7c00`.  Finally, [.filename]#boot1# is created from "
"[.filename]#boot1.out# applying the appropriate rule.  This rule is the "
"[.filename]#objcopy# command applied to [.filename]#boot1.out#.  Note the "
"flags passed to [.filename]#objcopy#: `-S` tells it to strip all relocation "
"and symbolic information; `-O binary` indicates the output format, that is, "
"a simple, unformatted binary file."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:801
msgid ""
"Having [.filename]#boot1#, let us take a look at how [.filename]#boot2# is "
"constructed:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:808
#, no-wrap
msgid ""
"      boot2: boot2.ld\n"
"\t@set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \\\n"
"\t    echo \"$$x bytes available\"; test $$x -ge 0\n"
"\t${DD} if=${.ALLSRC} of=${.TARGET} bs=${BOOT2SIZE} conv=sync\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:812
#, no-wrap
msgid ""
"      boot2.ld: boot2.ldr boot2.bin ${BTXKERN}\n"
"\tbtxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l boot2.ldr \\\n"
"\t    -o ${.TARGET} -P 1 boot2.bin\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:815
#, no-wrap
msgid ""
"      boot2.ldr:\n"
"\t${DD} if=/dev/zero of=${.TARGET} bs=512 count=1\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:818
#, no-wrap
msgid ""
"      boot2.bin: boot2.out\n"
"\t${OBJCOPY} -S -O binary boot2.out ${.TARGET}\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:821
#, no-wrap
msgid ""
"      boot2.out: ${BTXCRT} boot2.o sio.o ashldi3.o\n"
"\t${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC}\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:828
#, no-wrap
msgid ""
"      boot2.h: boot1.out\n"
"\t${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \\\n"
"\t    { x = $$1 - ORG1; \\\n"
"\t    printf(\"#define XREADORG %#x\\n\", REL1 + x) }' \\\n"
"\t    ORG1=`printf \"%d\" ${ORG1}` \\\n"
"\t    REL1=`printf \"%d\" ${REL1}` > ${.TARGET}\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:830
#, no-wrap
msgid "[.filename]#stand/i386/boot2/Makefile# [[boot-boot1-make-boot2]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:834
msgid ""
"The mechanism for building [.filename]#boot2# is far more elaborate.  Let us "
"point out the most relevant facts.  The dependency list is as follows:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:842
#, no-wrap
msgid ""
"      boot2: boot2.ld\n"
"      boot2.ld: boot2.ldr boot2.bin ${BTXDIR}\n"
"      boot2.bin: boot2.out\n"
"      boot2.out: ${BTXDIR} boot2.o sio.o ashldi3.o\n"
"      boot2.h: boot1.out\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:844
#, no-wrap
msgid "[.filename]#stand/i386/boot2/Makefile# [[boot-boot1-make-boot2-more]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:847
msgid ""
"Note that initially there is no header file [.filename]#boot2.h#, but its "
"creation depends on [.filename]#boot1.out#, which we already have.  The rule "
"for its creation is a bit terse, but the important thing is that the output, "
"[.filename]#boot2.h#, is something like this:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:851
#, no-wrap
msgid "#define XREADORG 0x725\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:853
#, no-wrap
msgid "[.filename]#stand/i386/boot2/boot2.h# [[boot-boot1-make-boot2h]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:859
msgid ""
"Recall that [.filename]#boot1# was relocated (i.e., copied from `0x7c00` to "
"`0x700`).  This relocation will now make sense, because as we will see, the "
"BTX server reclaims some memory, including the space where "
"[.filename]#boot1# was originally loaded.  However, the BTX server needs "
"access to [.filename]#boot1#'s `xread` function; this function, according to "
"the output of [.filename]#boot2.h#, is at location `0x725`.  Indeed, the BTX "
"server uses the `xread` function from [.filename]#boot1#'s relocated code.  "
"This function is now accessible from within the [.filename]#boot2# client."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:868
msgid ""
"The next rule directs the linker to link various files "
"([.filename]#ashldi3.o#, [.filename]#boot2.o# and [.filename]#sio.o#).  Note "
"that the output file, [.filename]#boot2.out#, is linked to execute at "
"address `0x2000` (${ORG2}).  Recall that [.filename]#boot2# will be executed "
"in user mode, within a special user segment set up by the BTX server.  This "
"segment starts at `0xa000`.  Also, remember that the [.filename]#boot2# "
"portion of [.filename]#boot# was copied to address `0xc000`, that is, offset "
"`0x2000` from the start of the user segment, so [.filename]#boot2# will work "
"properly when we transfer control to it.  Next, [.filename]#boot2.bin# is "
"created from [.filename]#boot2.out# by stripping its symbols and format "
"information; boot2.bin is a _raw_ binary.  Now, note that a file "
"[.filename]#boot2.ldr# is created as a 512-byte file full of zeros.  This "
"space is reserved for the bsdlabel."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:873
msgid ""
"Now that we have files [.filename]#boot1#, [.filename]#boot2.bin# and "
"[.filename]#boot2.ldr#, only the BTX server is missing before creating the "
"all-in-one [.filename]#boot# file.  The BTX server is located in "
"[.filename]#stand/i386/btx/btx#; it has its own [.filename]#Makefile# with "
"its own set of rules for building.  The important thing to notice is that it "
"is also compiled as a _raw_ binary, and that it is linked to execute at "
"address `0x9000`.  The details can be found in [.filename]#stand/i386/btx/"
"btx/Makefile#."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:880
msgid ""
"Having the files that comprise the [.filename]#boot# program, the final step "
"is to _merge_ them.  This is done by a special program called "
"[.filename]#btxld# (source located in [.filename]#/usr/src/usr.sbin/"
"btxld#).  Some arguments to this program include the name of the output file "
"([.filename]#boot#), its entry point (`0x2000`) and its file format (raw "
"binary).  The various files are finally merged by this utility into the file "
"[.filename]#boot#, which consists of [.filename]#boot1#, [.filename]#boot2#, "
"the `bsdlabel` and the BTX server.  This file, which takes exactly 16 "
"sectors, or 8192 bytes, is what is actually written to the beginning of the "
"FreeBSD slice during installation.  Let us now proceed to study the BTX "
"server program."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:883
msgid ""
"The BTX server prepares a simple environment and switches from 16-bit real "
"mode to 32-bit protected mode, right before passing control to the client.  "
"This includes initializing and updating the following data structures:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:886
msgid ""
"Modifies the `Interrupt Vector Table (IVT)`.  The IVT provides exception and "
"interrupt handlers for Real-Mode code."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:889
msgid ""
"The `Interrupt Descriptor Table (IDT)` is created.  Entries are provided for "
"processor exceptions, hardware interrupts, two system calls and V86 "
"interface.  The IDT provides exception and interrupt handlers for Protected-"
"Mode code."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:891
msgid ""
"A `Task-State Segment (TSS)` is created.  This is necessary because the "
"processor works in the _least_ privileged level when executing the client "
"([.filename]#boot2#), but in the _most_ privileged level when executing the "
"BTX server."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:894
msgid ""
"The GDT (Global Descriptor Table) is set up.  Entries (descriptors) are "
"provided for supervisor code and data, user code and data, and real-mode "
"code and data.  footnote:[Real-mode code and data are necessary when "
"switching back to real mode from protected mode, as suggested by the Intel "
"manuals.]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:899
msgid ""
"Let us now start studying the actual implementation.  Recall that "
"[.filename]#boot1# made a jump to address `0x9010`, the BTX server's entry "
"point.  Before studying program execution there, note that the BTX server "
"has a special header at address range `0x9000-0x900f`, right before its "
"entry point.  This header is defined as follows:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:915
#, no-wrap
msgid ""
"start:\t\t\t\t\t\t# Start of code\n"
"/*\n"
" * BTX header.\n"
" */\n"
"btx_hdr:\t.byte 0xeb\t\t\t# Machine ID\n"
"\t\t.byte 0xe\t\t\t# Header size\n"
"\t\t.ascii \"BTX\"\t\t\t# Magic\n"
"\t\t.byte 0x1\t\t\t# Major version\n"
"\t\t.byte 0x2\t\t\t# Minor version\n"
"\t\t.byte BTX_FLAGS\t\t\t# Flags\n"
"\t\t.word PAG_CNT-MEM_ORG>>0xc\t# Paging control\n"
"\t\t.word break-start\t\t# Text size\n"
"\t\t.long 0x0\t\t\t# Entry address\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:917
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-header]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:922
msgid ""
"Note the first two bytes are `0xeb` and `0xe`.  In the IA-32 architecture, "
"these two bytes are interpreted as a relative jump past the header into the "
"entry point, so in theory, [.filename]#boot1# could jump here (address "
"`0x9000`) instead of address `0x9010`.  Note that the last field in the BTX "
"header is a pointer to the client's ([.filename]#boot2#) entry pointb2.  "
"This field is patched at link time."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:924
msgid "Immediately following the header is the BTX server's entry point:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:938
#, no-wrap
msgid ""
"/*\n"
" * Initialization routine.\n"
" */\n"
"init:\t\tcli\t\t\t\t# Disable interrupts\n"
"\t\txor %ax,%ax\t\t\t# Zero/segment\n"
"\t\tmov %ax,%ss\t\t\t# Set up\n"
"\t\tmov $MEM_ESP0,%sp\t\t#  stack\n"
"\t\tmov %ax,%es\t\t\t# Address\n"
"\t\tmov %ax,%ds\t\t\t#  data\n"
"\t\tpushl $0x2\t\t\t# Clear\n"
"\t\tpopfl\t\t\t\t#  flags\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:940
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-init]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:944
msgid ""
"This code disables interrupts, sets up a working stack (starting at address "
"`0x1800`) and clears the flags in the EFLAGS register.  Note that the "
"`popfl` instruction pops out a doubleword (4 bytes) from the stack and "
"places it in the EFLAGS register.  As the value actually popped is `2`, the "
"EFLAGS register is effectively cleared (IA-32 requires that bit 2 of the "
"EFLAGS register always be 1)."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:947
msgid ""
"Our next code block clears (sets to `0`) the memory range `0x5e00-0x8fff`.  "
"This range is where the various data structures will be created:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:957
#, no-wrap
msgid ""
"/*\n"
" * Initialize memory.\n"
" */\n"
"\t\tmov $MEM_IDT,%di\t\t# Memory to initialize\n"
"\t\tmov $(MEM_ORG-MEM_IDT)/2,%cx\t# Words to zero\n"
"\t\trep\t\t\t\t# Zero-fill\n"
"\t\tstosw\t\t\t\t#  memory\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:959
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-clear-mem]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:962
msgid ""
"Recall that [.filename]#boot1# was originally loaded to address `0x7c00`, "
"so, with this memory initialization, that copy effectively disappeared.  "
"However, also recall that [.filename]#boot1# was relocated to `0x700`, so "
"_that_ copy is still in memory, and the BTX server will make use of it."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:970
msgid ""
"Next, the real-mode IVT (Interrupt Vector Table is updated.  The IVT is an "
"array of segment/offset pairs for exception and interrupt handlers.  The "
"BIOS normally maps hardware interrupts to interrupt vectors `0x8` to `0xf` "
"and `0x70` to `0x77` but, as will be seen, the 8259A Programmable Interrupt "
"Controller, the chip controlling the actual mapping of hardware interrupts "
"to interrupt vectors, is programmed to remap these interrupt vectors from "
"`0x8-0xf` to `0x20-0x27` and from `0x70-0x77` to `0x28-0x2f`.  Thus, "
"interrupt handlers are provided for interrupt vectors `0x20-0x2f`.  The "
"reason the BIOS-provided handlers are not used directly is because they work "
"in 16-bit real mode, but not 32-bit protected mode.  Processor mode will be "
"switched to 32-bit protected mode shortly.  However, the BTX server sets up "
"a mechanism to effectively use the handlers provided by the BIOS:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:985
#, no-wrap
msgid ""
"/*\n"
" * Update real mode IDT for reflecting hardware interrupts.\n"
" */\n"
"\t\tmov $intr20,%bx\t\t\t# Address first handler\n"
"\t\tmov $0x10,%cx\t\t\t# Number of handlers\n"
"\t\tmov $0x20*4,%di\t\t\t# First real mode IDT entry\n"
"init.0:\t\tmov %bx,(%di)\t\t\t# Store IP\n"
"\t\tinc %di\t\t\t\t# Address next\n"
"\t\tinc %di\t\t\t\t#  entry\n"
"\t\tstosw\t\t\t\t# Store CS\n"
"\t\tadd $4,%bx\t\t\t# Next handler\n"
"\t\tloop init.0\t\t\t# Next IRQ\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:987
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-ivt]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:992
msgid ""
"The next block creates the IDT (Interrupt Descriptor Table).  The IDT is "
"analogous, in protected mode, to the IVT in real mode.  That is, the IDT "
"describes the various exception and interrupt handlers used when the "
"processor is executing in protected mode.  In essence, it also consists of "
"an array of segment/offset pairs, although the structure is somewhat more "
"complex, because segments in protected mode are different than in real mode, "
"and various protection mechanisms apply:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1019
#, no-wrap
msgid ""
"/*\n"
" * Create IDT.\n"
" */\n"
"\t\tmov $MEM_IDT,%di\t\t# IDT's address\n"
"\t\tmov $idtctl,%si\t\t\t# Control string\n"
"init.1:\t\tlodsb\t\t\t\t# Get entry\n"
"\t\tcbw\t\t\t\t#  count\n"
"\t\txchg %ax,%cx\t\t\t#  as word\n"
"\t\tjcxz init.4\t\t\t# If done\n"
"\t\tlodsb\t\t\t\t# Get segment\n"
"\t\txchg %ax,%dx\t\t\t#  P:DPL:type\n"
"\t\tlodsw\t\t\t\t# Get control\n"
"\t\txchg %ax,%bx\t\t\t#  set\n"
"\t\tlodsw\t\t\t\t# Get handler offset\n"
"\t\tmov $SEL_SCODE,%dh\t\t# Segment selector\n"
"init.2:\t\tshr %bx\t\t\t\t# Handle this int?\n"
"\t\tjnc init.3\t\t\t# No\n"
"\t\tmov %ax,(%di)\t\t\t# Set handler offset\n"
"\t\tmov %dh,0x2(%di)\t\t#  and selector\n"
"\t\tmov %dl,0x5(%di)\t\t# Set P:DPL:type\n"
"\t\tadd $0x4,%ax\t\t\t# Next handler\n"
"init.3:\t\tlea 0x8(%di),%di\t\t# Next entry\n"
"\t\tloop init.2\t\t\t# Till set done\n"
"\t\tjmp init.1\t\t\t# Continue\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1021
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-idt]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1029
msgid ""
"Each entry in the `IDT` is 8 bytes long.  Besides the segment/offset "
"information, they also describe the segment type, privilege level, and "
"whether the segment is present in memory or not.  The construction is such "
"that interrupt vectors from `0` to `0xf` (exceptions) are handled by "
"function `intx00`; vector `0x10` (also an exception) is handled by `intx10`; "
"hardware interrupts, which are later configured to start at interrupt vector "
"`0x20` all the way to interrupt vector `0x2f`, are handled by function "
"`intx20`.  Lastly, interrupt vector `0x30`, which is used for system calls, "
"is handled by `intx30`, and vectors `0x31` and `0x32` are handled by "
"`intx31`.  It must be noted that only descriptors for interrupt vectors "
"`0x30`, `0x31` and `0x32` are given privilege level 3, the same privilege "
"level as the [.filename]#boot2# client, which means the client can execute a "
"software-generated interrupt to this vectors through the `int` instruction "
"without failing (this is the way [.filename]#boot2# use the services "
"provided by the BTX server).  Also, note that _only_ software-generated "
"interrupts are protected from code executing in lesser privilege levels.  "
"Hardware-generated interrupts and processor-generated exceptions are "
"_always_ handled adequately, regardless of the actual privileges involved."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1034
msgid ""
"The next step is to initialize the TSS (Task-State Segment).  The TSS is a "
"hardware feature that helps the operating system or executive software "
"implement multitasking functionality through process abstraction.  The IA-32 "
"architecture demands the creation and use of _at least_ one TSS if "
"multitasking facilities are used or different privilege levels are defined.  "
"Since the [.filename]#boot2# client is executed in privilege level 3, but "
"the BTX server runs in privilege level 0, a TSS must be defined:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1043
#, no-wrap
msgid ""
"/*\n"
" * Initialize TSS.\n"
" */\n"
"init.4:\t\tmovb $_ESP0H,TSS_ESP0+1(%di)\t# Set ESP0\n"
"\t\tmovb $SEL_SDATA,TSS_SS0(%di)\t# Set SS0\n"
"\t\tmovb $_TSSIO,TSS_MAP(%di)\t# Set I/O bit map base\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1045
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-tss]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1049
msgid ""
"Note that a value is given for the Privilege Level 0 stack pointer and stack "
"segment in the TSS.  This is needed because, if an interrupt or exception is "
"received while executing [.filename]#boot2# in Privilege Level 3, a change "
"to Privilege Level 0 is automatically performed by the processor, so a new "
"working stack is needed.  Finally, the I/O Map Base Address field of the TSS "
"is given a value, which is a 16-bit offset from the beginning of the TSS to "
"the I/O Permission Bitmap and the Interrupt Redirection Bitmap."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1052
msgid ""
"After the IDT and TSS are created, the processor is ready to switch to "
"protected mode.  This is done in the next block:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1070
#, no-wrap
msgid ""
"/*\n"
" * Bring up the system.\n"
" */\n"
"\t\tmov $0x2820,%bx\t\t\t# Set protected mode\n"
"\t\tcallw setpic\t\t\t#  IRQ offsets\n"
"\t\tlidt idtdesc\t\t\t# Set IDT\n"
"\t\tlgdt gdtdesc\t\t\t# Set GDT\n"
"\t\tmov %cr0,%eax\t\t\t# Switch to protected\n"
"\t\tinc %ax\t\t\t\t#  mode\n"
"\t\tmov %eax,%cr0\t\t\t#\n"
"\t\tljmp $SEL_SCODE,$init.8\t\t# To 32-bit code\n"
"\t\t.code32\n"
"init.8:\t\txorl %ecx,%ecx\t\t\t# Zero\n"
"\t\tmovb $SEL_SDATA,%cl\t\t# To 32-bit\n"
"\t\tmovw %cx,%ss\t\t\t#  stack\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1072
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-prot]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1085
msgid ""
"First, a call is made to `setpic` to program the 8259A PIC (Programmable "
"Interrupt Controller).  This chip is connected to multiple hardware "
"interrupt sources.  Upon receiving an interrupt from a device, it signals "
"the processor with the appropriate interrupt vector.  This can be customized "
"so that specific interrupts are associated with specific interrupt vectors, "
"as explained before.  Next, the IDTR (Interrupt Descriptor Table Register) "
"and GDTR (Global Descriptor Table Register) are loaded with the instructions "
"`lidt` and `lgdt`, respectively.  These registers are loaded with the base "
"address and limit address for the IDT and GDT.  The following three "
"instructions set the Protection Enable (PE) bit of the `%cr0` register.  "
"This effectively switches the processor to 32-bit protected mode.  Next, a "
"long jump is made to `init.8` using segment selector SEL_SCODE, which "
"selects the Supervisor Code Segment.  The processor is effectively executing "
"in CPL 0, the most privileged level, after this jump.  Finally, the "
"Supervisor Data Segment is selected for the stack by assigning the segment "
"selector SEL_SDATA to the `%ss` register.  This data segment also has a "
"privilege level of `0`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1087
msgid ""
"Our last code block is responsible for loading the TR (Task Register) with "
"the segment selector for the TSS we created earlier, and setting the User "
"Mode environment before passing execution control to the [.filename]#boot2# "
"client."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1123
#, no-wrap
msgid ""
"/*\n"
" * Launch user task.\n"
" */\n"
"\t\tmovb $SEL_TSS,%cl\t\t# Set task\n"
"\t\tltr %cx\t\t\t\t#  register\n"
"\t\tmovl $MEM_USR,%edx\t\t# User base address\n"
"\t\tmovzwl %ss:BDA_MEM,%eax\t\t# Get free memory\n"
"\t\tshll $0xa,%eax\t\t\t# To bytes\n"
"\t\tsubl $ARGSPACE,%eax\t\t# Less arg space\n"
"\t\tsubl %edx,%eax\t\t\t# Less base\n"
"\t\tmovb $SEL_UDATA,%cl\t\t# User data selector\n"
"\t\tpushl %ecx\t\t\t# Set SS\n"
"\t\tpushl %eax\t\t\t# Set ESP\n"
"\t\tpush $0x202\t\t\t# Set flags (IF set)\n"
"\t\tpush $SEL_UCODE\t\t\t# Set CS\n"
"\t\tpushl btx_hdr+0xc\t\t# Set EIP\n"
"\t\tpushl %ecx\t\t\t# Set GS\n"
"\t\tpushl %ecx\t\t\t# Set FS\n"
"\t\tpushl %ecx\t\t\t# Set DS\n"
"\t\tpushl %ecx\t\t\t# Set ES\n"
"\t\tpushl %edx\t\t\t# Set EAX\n"
"\t\tmovb $0x7,%cl\t\t\t# Set remaining\n"
"init.9:\t\tpush $0x0\t\t\t#  general\n"
"\t\tloop init.9\t\t\t#  registers\n"
"#ifdef BTX_SERIAL\n"
"\t\tcall sio_init\t\t\t# setup the serial console\n"
"#endif\n"
"\t\tpopa\t\t\t\t#  and initialize\n"
"\t\tpopl %es\t\t\t# Initialize\n"
"\t\tpopl %ds\t\t\t#  user\n"
"\t\tpopl %fs\t\t\t#  segment\n"
"\t\tpopl %gs\t\t\t#  registers\n"
"\t\tiret\t\t\t\t# To user mode\n"
msgstr ""

#. type: Block title
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1125
#, no-wrap
msgid "[.filename]#stand/i386/btx/btx/btx.S# [[btx-end]]"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1149
msgid ""
"Note that the client's environment include a stack segment selector and "
"stack pointer (registers `%ss` and `%esp`).  Indeed, once the TR is loaded "
"with the appropriate stack segment selector (instruction `ltr`), the stack "
"pointer is calculated and pushed onto the stack along with the stack's "
"segment selector.  Next, the value `0x202` is pushed onto the stack; it is "
"the value that the EFLAGS will get when control is passed to the client.  "
"Also, the User Mode code segment selector and the client's entry point are "
"pushed.  Recall that this entry point is patched in the BTX header at link "
"time.  Finally, segment selectors (stored in register `%ecx`) for the "
"segment registers `%gs, %fs, %ds and %es` are pushed onto the stack, along "
"with the value at `%edx` (`0xa000`).  Keep in mind the various values that "
"have been pushed onto the stack (they will be popped out shortly).  Next, "
"values for the remaining general purpose registers are also pushed onto the "
"stack (note the `loop` that pushes the value `0` seven times).  Now, values "
"will be started to be popped out of the stack.  First, the `popa` "
"instruction pops out of the stack the latest seven values pushed.  They are "
"stored in the general purpose registers in order `%edi, %esi, %ebp, %ebx, "
"%edx, %ecx, %eax`.  Then, the various segment selectors pushed are popped "
"into the various segment registers.  Five values still remain on the stack.  "
"They are popped when the `iret` instruction is executed.  This instruction "
"first pops the value that was pushed from the BTX header.  This value is a "
"pointer to [.filename]#boot2#'s entry point.  It is placed in the register "
"`%eip`, the instruction pointer register.  Next, the segment selector for "
"the User Code Segment is popped and copied to register `%cs`.  Remember that "
"this segment's privilege level is 3, the least privileged level.  This means "
"that we must provide values for the stack of this privilege level.  This is "
"why the processor, besides further popping the value for the EFLAGS "
"register, does two more pops out of the stack.  These values go to the stack "
"pointer (`%esp`) and the stack segment (`%ss`).  Now, execution continues at "
"``boot0``'s entry point."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1153
msgid ""
"It is important to note how the User Code Segment is defined.  This "
"segment's _base address_ is set to `0xa000`.  This means that code memory "
"addresses are _relative_ to address 0xa000; if code being executed is "
"fetched from address `0x2000`, the _actual_ memory addressed is "
"`0xa000+0x2000=0xc000`."
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1155
#, no-wrap
msgid "boot2 Stage"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1162
msgid ""
"`boot2` defines an important structure, `struct bootinfo`.  This structure "
"is initialized by `boot2` and passed to the loader, and then further to the "
"kernel.  Some nodes of this structures are set by `boot2`, the rest by the "
"loader.  This structure, among other information, contains the kernel "
"filename, BIOS harddisk geometry, BIOS drive number for boot device, "
"physical memory available, `envp` pointer etc.  The definition for it is:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1187
#, no-wrap
msgid ""
"/usr/include/machine/bootinfo.h:\n"
"struct bootinfo {\n"
"\tu_int32_t\tbi_version;\n"
"\tu_int32_t\tbi_kernelname;\t\t/* represents a char * */\n"
"\tu_int32_t\tbi_nfs_diskless;\t/* struct nfs_diskless * */\n"
"\t\t\t\t/* End of fields that are always present. */\n"
"#define\tbi_endcommon\tbi_n_bios_used\n"
"\tu_int32_t\tbi_n_bios_used;\n"
"\tu_int32_t\tbi_bios_geom[N_BIOS_GEOM];\n"
"\tu_int32_t\tbi_size;\n"
"\tu_int8_t\tbi_memsizes_valid;\n"
"\tu_int8_t\tbi_bios_dev;\t\t/* bootdev BIOS unit number */\n"
"\tu_int8_t\tbi_pad[2];\n"
"\tu_int32_t\tbi_basemem;\n"
"\tu_int32_t\tbi_extmem;\n"
"\tu_int32_t\tbi_symtab;\t\t/* struct symtab * */\n"
"\tu_int32_t\tbi_esymtab;\t\t/* struct symtab * */\n"
"\t\t\t\t/* Items below only from advanced bootloader */\n"
"\tu_int32_t\tbi_kernend;\t\t/* end of kernel space */\n"
"\tu_int32_t\tbi_envp;\t\t/* environment */\n"
"\tu_int32_t\tbi_modulep;\t\t/* preloaded modules */\n"
"};\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1194
msgid ""
"`boot2` enters into an infinite loop waiting for user input, then calls "
"`load()`.  If the user does not press anything, the loop breaks by a "
"timeout, so `load()` will load the default file ([.filename]#/boot/"
"loader#).  Functions `ino_t lookup(char *filename)` and `int xfsread(ino_t "
"inode, void *buf, size_t nbyte)` are used to read the content of a file into "
"memory.  [.filename]#/boot/loader# is an ELF binary, but where the ELF "
"header is prepended with [.filename]#a.out#'s `struct exec` structure.  "
"`load()` scans the loader's ELF header, loading the content of [.filename]#/"
"boot/loader# into memory, and passing the execution to the loader's entry:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1201
#, no-wrap
msgid ""
"stand/i386/boot2/boot2.c:\n"
"    __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),\n"
"\t   MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part),\n"
"\t   0, 0, 0, VTOP(&bootinfo));\n"
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1204
#, no-wrap
msgid "loader Stage"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1209
msgid ""
"loader is a BTX client as well.  I will not describe it here in detail, "
"there is a comprehensive man page written by Mike Smith, man:loader[8].  The "
"underlying mechanisms and BTX were discussed above."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1212
msgid ""
"The main task for the loader is to boot the kernel.  When the kernel is "
"loaded into memory, it is being called by the loader:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1218
#, no-wrap
msgid ""
"stand/common/boot.c:\n"
"    /* Call the exec handler from the loader matching the kernel */\n"
"    file_formats[fp->f_loader]->l_exec(fp);\n"
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1221
#, no-wrap
msgid "Kernel Initialization"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1228
msgid ""
"Let us take a look at the command that links the kernel.  This will help "
"identify the exact location where the loader passes execution to the "
"kernel.  This location is the kernel's actual entry point.  This command is "
"now excluded from [.filename]#sys/conf/Makefile.i386#.  The content that "
"interests us can be found in [.filename]#/usr/obj/usr/src/i386.i386/sys/"
"GENERIC/#."
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1235
#, no-wrap
msgid ""
"/usr/obj/usr/src/i386.i386/sys/GENERIC/kernel.meta:\n"
"ld -m elf_i386_fbsd -Bdynamic -T /usr/src/sys/conf/ldscript.i386 --build-id=sha1 --no-warn-mismatch \\\n"
"--warn-common --export-dynamic  --dynamic-linker /red/herring -X -o kernel locore.o\n"
"<lots of kernel .o files>\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1241
msgid ""
"A few interesting things can be seen here.  First, the kernel is an ELF "
"dynamically linked binary, but the dynamic linker for kernel is [.filename]#/"
"red/herring#, which is definitely a bogus file.  Second, taking a look at "
"the file [.filename]#sys/conf/ldscript.i386# gives an idea about what ld "
"options are used when compiling a kernel.  Reading through the first few "
"lines, the string"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1246
#, no-wrap
msgid ""
"sys/conf/ldscript.i386:\n"
"ENTRY(btext)\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1250
msgid ""
"says that a kernel's entry point is the symbol `btext`.  This symbol is "
"defined in [.filename]#locore.s#:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1261
#, no-wrap
msgid ""
"sys/i386/i386/locore.s:\n"
"\t.text\n"
"/**********************************************************************\n"
" *\n"
" * This is where the bootblocks start us, set the ball rolling...\n"
" *\n"
" */\n"
"NON_GPROF_ENTRY(btext)\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1265
msgid ""
"First, the register EFLAGS is set to a predefined value of 0x00000002.  Then "
"all the segment registers are initialized:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1272
#, no-wrap
msgid ""
"sys/i386/i386/locore.s:\n"
"/* Don't trust what the BIOS gives for eflags. */\n"
"\tpushl\t$PSL_KERNEL\n"
"\tpopfl\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1280
#, no-wrap
msgid ""
"/*\n"
" * Don't trust what the BIOS gives for %fs and %gs.  Trust the bootstrap\n"
" * to set %cs, %ds, %es and %ss.\n"
" */\n"
"\tmov\t%ds, %ax\n"
"\tmov\t%ax, %fs\n"
"\tmov\t%ax, %gs\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1284
msgid ""
"btext calls the routines `recover_bootinfo()`, `identify_cpu()`, which are "
"also defined in [.filename]#locore.s#.  Here is a description of what they "
"do:"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1290
#, no-wrap
msgid "`recover_bootinfo`"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1294
#, no-wrap
msgid ""
"This routine parses the parameters to the kernel passed from the bootstrap.\n"
"The kernel may have been booted in 3 ways: by the loader, described above, by the old disk boot blocks, or by the old diskless boot procedure.\n"
"This function determines the booting method, and stores the `struct bootinfo` structure into the kernel memory."
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1295
#, no-wrap
msgid "`identify_cpu`"
msgstr ""

#. type: Table
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1296
#, no-wrap
msgid "This function tries to find out what CPU it is running on, storing the value found in a variable `_cpu`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1299
msgid "The next steps are enabling VME, if the CPU supports it:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1307
#, no-wrap
msgid ""
"sys/i386/i386/mpboot.s:\n"
"\ttestl\t$CPUID_VME,%edx\n"
"\tjz\t3f\n"
"\torl\t$CR4_VME,%eax\n"
"3:\tmovl\t%eax,%cr4\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1310
msgid "Then, enabling paging:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1320
#, no-wrap
msgid ""
"sys/i386/i386/mpboot.s:\n"
"/* Now enable paging */\n"
"\tmovl\tIdlePTD_nopae, %eax\n"
"\tmovl\t%eax,%cr3\t\t\t/* load ptd addr into mmu */\n"
"\tmovl\t%cr0,%eax\t\t\t/* get control word */\n"
"\torl\t$CR0_PE|CR0_PG,%eax\t\t/* enable paging */\n"
"\tmovl\t%eax,%cr0\t\t\t/* and let's page NOW! */\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1323
msgid ""
"The next three lines of code are because the paging was set, so the jump is "
"needed to continue the execution in virtualized address space:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1329
#, no-wrap
msgid ""
"sys/i386/i386/mpboot.s:\n"
"\tpushl\t$mp_begin\t\t\t\t/* jump to high mem */\n"
"\tret\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1332
#, no-wrap
msgid ""
"/* now running relocated at KERNBASE where the system is linked to run */\n"
"mp_begin:\t/* now running relocated at KERNBASE */\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1337
msgid ""
"The function `init386()` is called with a pointer to the first free physical "
"page, after that `mi_startup()`.  `init386` is an architecture dependent "
"initialization function, and `mi_startup()` is an architecture independent "
"one (the 'mi_' prefix stands for Machine Independent).  The kernel never "
"returns from `mi_startup()`, and by calling it, the kernel finishes booting:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1347
#, no-wrap
msgid ""
"sys/i386/i386/locore.s:\n"
"\tpushl\tphysfree\t\t\t/* value of first for init386(first) */\n"
"\tcall\tinit386\t\t\t\t/* wire 386 chip for unix operation */\n"
"\taddl\t$4,%esp\n"
"\tmovl\t%eax,%esp\t\t\t/* Switch to true top of stack. */\n"
"\tcall\tmi_startup\t\t\t/* autoconfiguration, mountroot etc */\n"
"\t/* NOTREACHED */\n"
msgstr ""

#. type: Title ===
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1349
#, no-wrap
msgid "`init386()`"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1354
msgid ""
"`init386()` is defined in [.filename]#sys/i386/i386/machdep.c# and performs "
"low-level initialization specific to the i386 chip. The switch to protected "
"mode was performed by the loader.  The loader has created the very first "
"task, in which the kernel continues to operate.  Before looking at the code, "
"consider the tasks the processor must complete to initialize protected mode "
"execution:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1356
msgid ""
"Initialize the kernel tunable parameters, passed from the bootstrapping "
"program."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1357
msgid "Prepare the GDT."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1358
msgid "Prepare the IDT."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1359
msgid "Initialize the system console."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1360
msgid "Initialize the DDB, if it is compiled into kernel."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1361
msgid "Initialize the TSS."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1362
msgid "Prepare the LDT."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1363
msgid "Set up thread0's pcb."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1366
msgid ""
"`init386()` initializes the tunable parameters passed from bootstrap by "
"setting the environment pointer (envp) and calling `init_param1()`.  The "
"envp pointer has been passed from loader in the `bootinfo` structure:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1372
#, no-wrap
msgid ""
"sys/i386/i386/machdep.c:\n"
"\t/* Init basic tunables, hz etc */\n"
"\tinit_param1();\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1376
msgid ""
"`init_param1()` is defined in [.filename]#sys/kern/subr_param.c#.  That file "
"has a number of sysctls, and two functions, `init_param1()` and "
"`init_param2()`, that are called from `init386()`:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1384
#, no-wrap
msgid ""
"sys/kern/subr_param.c:\n"
"\thz = -1;\n"
"\tTUNABLE_INT_FETCH(\"kern.hz\", &hz);\n"
"\tif (hz == -1)\n"
"\t\thz = vm_guest > VM_GUEST_NO ? HZ_VM : HZ;\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1387
msgid ""
"TUNABLE_<typename>_FETCH is used to fetch the value from the environment:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1392
#, no-wrap
msgid ""
"/usr/src/sys/sys/kernel.h:\n"
"#define\tTUNABLE_INT_FETCH(path, var)\tgetenv_int((path), (var))\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1396
msgid ""
"Sysctl `kern.hz` is the system clock tick.  Additionally, these sysctls are "
"set by `init_param1()`: `kern.maxswzone, kern.maxbcache, kern.maxtsiz, "
"kern.dfldsiz, kern.maxdsiz, kern.dflssiz, kern.maxssiz, kern.sgrowsiz`."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1404
msgid ""
"Then `init386()` prepares the Global Descriptors Table (GDT).  Every task on "
"an x86 is running in its own virtual address space, and this space is "
"addressed by a segment:offset pair.  Say, for instance, the current "
"instruction to be executed by the processor lies at CS:EIP, then the linear "
"virtual address for that instruction would be \"the virtual address of code "
"segment CS\" + EIP.  For convenience, segments begin at virtual address 0 "
"and end at a 4GB boundary.  Therefore, the instruction's linear virtual "
"address for this example would just be the value of EIP.  Segment registers "
"such as CS, DS etc are the selectors, i.e., indexes, into GDT (to be more "
"precise, an index is not a selector itself, but the INDEX field of a "
"selector).  FreeBSD's GDT holds descriptors for 15 selectors per CPU:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1410
#, no-wrap
msgid ""
"sys/i386/i386/machdep.c:\n"
"union descriptor gdt0[NGDT];\t/* initial global descriptor table */\n"
"union descriptor *gdt = gdt0;\t/* global descriptor table */\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1435
#, no-wrap
msgid ""
"sys/x86/include/segments.h:\n"
"/*\n"
" * Entries in the Global Descriptor Table (GDT)\n"
" */\n"
"#define\tGNULL_SEL\t0\t/* Null Descriptor */\n"
"#define\tGPRIV_SEL\t1\t/* SMP Per-Processor Private Data */\n"
"#define\tGUFS_SEL\t2\t/* User %fs Descriptor (order critical: 1) */\n"
"#define\tGUGS_SEL\t3\t/* User %gs Descriptor (order critical: 2) */\n"
"#define\tGCODE_SEL\t4\t/* Kernel Code Descriptor (order critical: 1) */\n"
"#define\tGDATA_SEL\t5\t/* Kernel Data Descriptor (order critical: 2) */\n"
"#define\tGUCODE_SEL\t6\t/* User Code Descriptor (order critical: 3) */\n"
"#define\tGUDATA_SEL\t7\t/* User Data Descriptor (order critical: 4) */\n"
"#define\tGBIOSLOWMEM_SEL\t8\t/* BIOS low memory access (must be entry 8) */\n"
"#define\tGPROC0_SEL\t9\t/* Task state process slot zero and up */\n"
"#define\tGLDT_SEL\t10\t/* Default User LDT */\n"
"#define\tGUSERLDT_SEL\t11\t/* User LDT */\n"
"#define\tGPANIC_SEL\t12\t/* Task state to consider panic from */\n"
"#define\tGBIOSCODE32_SEL\t13\t/* BIOS interface (32bit Code) */\n"
"#define\tGBIOSCODE16_SEL\t14\t/* BIOS interface (16bit Code) */\n"
"#define\tGBIOSDATA_SEL\t15\t/* BIOS interface (Data) */\n"
"#define\tGBIOSUTIL_SEL\t16\t/* BIOS interface (Utility) */\n"
"#define\tGBIOSARGS_SEL\t17\t/* BIOS interface (Arguments) */\n"
"#define\tGNDIS_SEL\t18\t/* For the NDIS layer */\n"
"#define\tNGDT\t\t19\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1439
msgid ""
"Note that those #defines are not selectors themselves, but just a field "
"INDEX of a selector, so they are exactly the indices of the GDT.  for "
"example, an actual selector for the kernel code (GCODE_SEL) has the value "
"0x20."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1447
msgid ""
"The next step is to initialize the Interrupt Descriptor Table (IDT).  This "
"table is referenced by the processor when a software or hardware interrupt "
"occurs.  For example, to make a system call, user application issues the "
"`INT 0x80` instruction.  This is a software interrupt, so the processor's "
"hardware looks up a record with index 0x80 in the IDT.  This record points "
"to the routine that handles this interrupt, in this particular case, this "
"will be the kernel's syscall gate.  The IDT may have a maximum of 256 "
"(0x100) records.  The kernel allocates NIDT records for the IDT, where NIDT "
"is the maximum (256):"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1453
#, no-wrap
msgid ""
"sys/i386/i386/machdep.c:\n"
"static struct gate_descriptor idt0[NIDT];\n"
"struct gate_descriptor *idt = &idt0[0];\t/* interrupt descriptor table */\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1457
msgid ""
"For each interrupt, an appropriate handler is set.  The syscall gate for "
"`INT 0x80` is set as well:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1463
#, no-wrap
msgid ""
"sys/i386/i386/machdep.c:\n"
"\tsetidt(IDT_SYSCALL, &IDTVEC(int0x80_syscall),\n"
"\t\t\tSDT_SYS386IGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1466
msgid ""
"So when a userland application issues the `INT 0x80` instruction, control "
"will transfer to the function `_Xint0x80_syscall`, which is in the kernel "
"code segment and will be executed with supervisor privileges."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1468
msgid "Console and DDB are then initialized:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1479
#, no-wrap
msgid ""
"sys/i386/i386/machdep.c:\n"
"\tcninit();\n"
"/* skipped */\n"
"  kdb_init();\n"
"#ifdef KDB\n"
"\tif (boothowto & RB_KDB)\n"
"\t\tkdb_enter(KDB_WHY_BOOTFLAGS, \"Boot flags requested debugger\");\n"
"#endif\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1482
msgid ""
"The Task State Segment is another x86 protected mode structure, the TSS is "
"used by the hardware to store task information when a task switch occurs."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1485
msgid ""
"The Local Descriptors Table is used to reference userland code and data.  "
"Several selectors are defined to point to the LDT, they are the system call "
"gates and the user code and data selectors:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1494
#, no-wrap
msgid ""
"sys/x86/include/segments.h:\n"
"#define\tLSYS5CALLS_SEL\t0\t/* forced by intel BCS */\n"
"#define\tLSYS5SIGR_SEL\t1\n"
"#define\tLUCODE_SEL\t3\n"
"#define\tLUDATA_SEL\t5\n"
"#define\tNLDT\t\t(LUDATA_SEL + 1)\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1499
msgid ""
"Next, proc0's Process Control Block (`struct pcb`) structure is "
"initialized.  proc0 is a `struct proc` structure that describes a kernel "
"process.  It is always present while the kernel is running, therefore it is "
"linked with thread0:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1507
#, no-wrap
msgid ""
"sys/i386/i386/machdep.c:\n"
"register_t\n"
"init386(int first)\n"
"{\n"
"    /* ... skipped ... */\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1511
#, no-wrap
msgid ""
"    proc_linkup0(&proc0, &thread0);\n"
"    /* ... skipped ... */\n"
"}\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1515
msgid ""
"The structure `struct pcb` is a part of a proc structure.  It is defined in "
"[.filename]#/usr/include/machine/pcb.h# and has a process's information "
"specific to the i386 architecture, such as registers values."
msgstr ""

#. type: Title ===
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1516
#, no-wrap
msgid "`mi_startup()`"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1519
msgid ""
"This function performs a bubble sort of all the system initialization "
"objects and then calls the entry of each object one by one:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1524
#, no-wrap
msgid ""
"sys/kern/init_main.c:\n"
"\tfor (sipp = sysinit; sipp < sysinit_end; sipp++) {\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1526
#, no-wrap
msgid "\t\t/* ... skipped ... */\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1531
#, no-wrap
msgid ""
"\t\t/* Call function */\n"
"\t\t(*((*sipp)->func))((*sipp)->udata);\n"
"\t\t/* ... skipped ... */\n"
"\t}\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1534
msgid ""
"Although the sysinit framework is described in the extref:{developers-"
"handbook}[Developers' Handbook], I will discuss the internals of it."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1538
msgid ""
"Every system initialization object (sysinit object) is created by calling a "
"SYSINIT() macro.  Let us take as example an `announce` sysinit object.  This "
"object prints the copyright message:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1549
#, no-wrap
msgid ""
"sys/kern/init_main.c:\n"
"static void\n"
"print_caddr_t(void *data __unused)\n"
"{\n"
"\tprintf(\"%s\", (char *)data);\n"
"}\n"
"/* ... skipped ... */\n"
"SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright);\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1553
msgid ""
"The subsystem ID for this object is SI_SUB_COPYRIGHT (0x0800001).  So, the "
"copyright message will be printed out first, just after the console "
"initialization."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1557
msgid ""
"Let us take a look at what exactly the macro `SYSINIT()` does.  It expands "
"to a `C_SYSINIT()` macro.  The `C_SYSINIT()` macro then expands to a static "
"`struct sysinit` structure declaration with another `DATA_SET` macro call:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1565
#, no-wrap
msgid ""
"/usr/include/sys/kernel.h:\n"
"      #define C_SYSINIT(uniquifier, subsystem, order, func, ident) \\\n"
"      static struct sysinit uniquifier ## _sys_init = { \\ subsystem, \\\n"
"      order, \\ func, \\ (ident) \\ }; \\ DATA_WSET(sysinit_set,uniquifier ##\n"
"      _sys_init);\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1569
#, no-wrap
msgid ""
"#define\tSYSINIT(uniquifier, subsystem, order, func, ident)\t\\\n"
"\tC_SYSINIT(uniquifier, subsystem, order,\t\t\t\\\n"
"\t(sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)(ident))\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1572
msgid ""
"The `DATA_SET()` macro expands to a `_MAKE_SET()`, and that macro is the "
"point where all the sysinit magic is hidden:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1578
#, no-wrap
msgid ""
"/usr/include/linker_set.h:\n"
"#define TEXT_SET(set, sym) _MAKE_SET(set, sym)\n"
"#define DATA_SET(set, sym) _MAKE_SET(set, sym)\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1582
msgid ""
"After executing these macros, various sections were made in the kernel, "
"including`set.sysinit_set`.  Running objdump on a kernel binary, you may "
"notice the presence of such small sections:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1594
#, no-wrap
msgid ""
"% llvm-objdump -h /kernel\n"
"Sections:\n"
"Idx Name                               Size     VMA      Type\n"
" 10 set_sysctl_set                     000021d4 01827078 DATA\n"
" 16 set_kbddriver_set                  00000010 0182a4d0 DATA\n"
" 20 set_scterm_set                     0000000c 0182c75c DATA\n"
" 21 set_cons_set                       00000014 0182c768 DATA\n"
" 33 set_scrndr_set                     00000024 0182c828 DATA\n"
" 41 set_sysinit_set                    000014d8 018fabb0 DATA\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1598
msgid ""
"This screen dump shows that the size of set.sysinit_set section is 0x14d8 "
"bytes, so `0x14d8/sizeof(void *)` sysinit objects are compiled into the "
"kernel.  The other sections such as `set.sysctl_set` represent other linker "
"sets."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1600
msgid ""
"By defining a variable of type `struct sysinit` the content of "
"`set.sysinit_set` section will be \"collected\" into that variable:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1605
#, no-wrap
msgid ""
"sys/kern/init_main.c:\n"
"  SET_DECLARE(sysinit_set, struct sysinit);\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1608
msgid "The `struct sysinit` is defined as follows:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1618
#, no-wrap
msgid ""
"sys/sys/kernel.h:\n"
"  struct sysinit {\n"
"\tenum sysinit_sub_id\tsubsystem;\t/* subsystem identifier*/\n"
"\tenum sysinit_elem_order\torder;\t\t/* init order within subsystem*/\n"
"\tsysinit_cfunc_t func;\t\t\t/* function\t\t*/\n"
"\tconst void\t*udata;\t\t\t/* multiplexer/argument */\n"
"};\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1623
msgid ""
"Returning to the `mi_startup()` discussion, it is must be clear now, how the "
"sysinit objects are being organized.  The `mi_startup()` function sorts them "
"and calls each.  The very last object is the system scheduler:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1635
#, no-wrap
msgid ""
"/usr/include/sys/kernel.h:\n"
"enum sysinit_sub_id {\n"
"\tSI_SUB_DUMMY\t\t= 0x0000000,\t/* not executed; for linker*/\n"
"\tSI_SUB_DONE\t\t= 0x0000001,\t/* processed*/\n"
"\tSI_SUB_TUNABLES\t\t= 0x0700000,\t/* establish tunable values */\n"
"\tSI_SUB_COPYRIGHT\t= 0x0800001,\t/* first use of console*/\n"
"...\n"
"\tSI_SUB_LAST\t\t= 0xfffffff\t/* final initialization */\n"
"};\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1640
msgid ""
"The system scheduler sysinit object is defined in the file [.filename]#sys/"
"vm/vm_glue.c#, and the entry point for that object is `scheduler()`.  That "
"function is actually an infinite loop, and it represents a process with PID "
"0, the swapper process.  The thread0 structure, mentioned before, is used to "
"describe it."
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1642
msgid ""
"The first user process, called _init_, is created by the sysinit object "
"`init`:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1653
#, no-wrap
msgid ""
"sys/kern/init_main.c:\n"
"static void\n"
"create_init(const void *udata __unused)\n"
"{\n"
"\tstruct fork_req fr;\n"
"\tstruct ucred *newcred, *oldcred;\n"
"\tstruct thread *td;\n"
"\tint error;\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1686
#, no-wrap
msgid ""
"\tbzero(&fr, sizeof(fr));\n"
"\tfr.fr_flags = RFFDG | RFPROC | RFSTOPPED;\n"
"\tfr.fr_procp = &initproc;\n"
"\terror = fork1(&thread0, &fr);\n"
"\tif (error)\n"
"\t\tpanic(\"cannot fork init: %d\\n\", error);\n"
"\tKASSERT(initproc->p_pid == 1, (\"create_init: initproc->p_pid != 1\"));\n"
"\t/* divorce init's credentials from the kernel's */\n"
"\tnewcred = crget();\n"
"\tsx_xlock(&proctree_lock);\n"
"\tPROC_LOCK(initproc);\n"
"\tinitproc->p_flag |= P_SYSTEM | P_INMEM;\n"
"\tinitproc->p_treeflag |= P_TREE_REAPER;\n"
"\toldcred = initproc->p_ucred;\n"
"\tcrcopy(newcred, oldcred);\n"
"#ifdef MAC\n"
"\tmac_cred_create_init(newcred);\n"
"#endif\n"
"#ifdef AUDIT\n"
"\taudit_cred_proc1(newcred);\n"
"#endif\n"
"\tproc_set_cred(initproc, newcred);\n"
"\ttd = FIRST_THREAD_IN_PROC(initproc);\n"
"\tcrcowfree(td);\n"
"\ttd->td_realucred = crcowget(initproc->p_ucred);\n"
"\ttd->td_ucred = td->td_realucred;\n"
"\tPROC_UNLOCK(initproc);\n"
"\tsx_xunlock(&proctree_lock);\n"
"\tcrfree(oldcred);\n"
"\tcpu_fork_kthread_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);\n"
"}\n"
"SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL);\n"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1692
msgid ""
"The function `create_init()` allocates a new process by calling `fork1()`, "
"but does not mark it runnable.  When this new process is scheduled for "
"execution by the scheduler, the `start_init()` will be called.  That "
"function is defined in [.filename]#init_main.c#.  It tries to load and exec "
"the [.filename]#init# binary, probing [.filename]#/sbin/init# first, then "
"[.filename]#/sbin/oinit#, [.filename]#/sbin/init.bak#, and finally "
"[.filename]#/rescue/init#:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/boot/_index.adoc:1702
#, no-wrap
msgid ""
"sys/kern/init_main.c:\n"
"static char init_path[MAXPATHLEN] =\n"
"#ifdef\tINIT_PATH\n"
"    __XSTRING(INIT_PATH);\n"
"#else\n"
"    \"/sbin/init:/sbin/oinit:/sbin/init.bak:/rescue/init\";\n"
"#endif\n"
msgstr ""