Whitespace-only fixes to indentation and line wrap. Translators may

ignore.

Approved by:	gjb (mentor)
This commit is contained in:
Warren Block 2012-01-10 02:50:25 +00:00
parent b3a79080bd
commit 75e065b0fa
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=38171

View file

@ -67,36 +67,29 @@ $FreeBSD$
<tbody> <tbody>
<row> <row>
<entry><para>Output (may vary)</para></entry> <entry><para>Output (may vary)</para></entry>
<entry><para>BIOS (firmware) messages</para></entry> <entry><para>BIOS (firmware) messages</para></entry>
</row> </row>
<row> <row>
<entry><para> <entry><para><screen>F1 FreeBSD
<screen>F1 FreeBSD
F2 BSD F2 BSD
F5 Disk 2</screen> F5 Disk 2</screen></para></entry>
</para></entry>
<entry><para><literal>boot0</literal></para></entry> <entry><para><literal>boot0</literal></para></entry>
</row> </row>
<row> <row>
<entry><para> <entry><para><screen>&gt;&gt;FreeBSD/i386 BOOT
<screen>&gt;&gt;FreeBSD/i386 BOOT
Default: 1:ad(1,a)/boot/loader Default: 1:ad(1,a)/boot/loader
boot:</screen> boot:</screen></para></entry>
</para></entry>
<entry><para><literal>boot2</literal><footnote><para>This <entry><para><literal>boot2</literal><footnote><para>This
prompt will appear if the user presses a key just after prompt will appear if the user presses a key just
selecting an OS to boot at the <literal>boot0</literal> after selecting an OS to boot at the
<literal>boot0</literal>
stage.</para></footnote></para></entry> stage.</para></footnote></para></entry>
</row> </row>
<row> <row>
<entry><para> <entry><para><screen>BTX loader 1.0 BTX version is 1.01
<screen>BTX loader 1.0 BTX version is 1.01
BIOS drive A: is disk0 BIOS drive A: is disk0
BIOS drive C: is disk1 BIOS drive C: is disk1
BIOS 639kB/64512kB available memory BIOS 639kB/64512kB available memory
@ -105,21 +98,17 @@ Console internal video/keyboard
(jkh@bento.freebsd.org, Mon Nov 20 11:41:23 GMT 2000) (jkh@bento.freebsd.org, Mon Nov 20 11:41:23 GMT 2000)
/kernel text=0x1234 data=0x2345 syms=[0x4+0x3456] /kernel text=0x1234 data=0x2345 syms=[0x4+0x3456]
Hit [Enter] to boot immediately, or any other key for command prompt Hit [Enter] to boot immediately, or any other key for command prompt
Booting [kernel] in 9 seconds..._</screen> Booting [kernel] in 9 seconds..._</screen></para></entry>
</para></entry>
<entry><para>loader</para></entry> <entry><para>loader</para></entry>
</row> </row>
<row> <row>
<entry><para> <entry><para><screen>Copyright (c) 1992-2002 The FreeBSD Project.
<screen>Copyright (c) 1992-2002 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved. The Regents of the University of California. All rights reserved.
FreeBSD 4.6-RC #0: Sat May 4 22:49:02 GMT 2002 FreeBSD 4.6-RC #0: Sat May 4 22:49:02 GMT 2002
devnull@kukas:/usr/obj/usr/src/sys/DEVNULL devnull@kukas:/usr/obj/usr/src/sys/DEVNULL
Timecounter "i8254" frequency 1193182 Hz</screen></para></entry> Timecounter "i8254" frequency 1193182 Hz</screen></para></entry>
<entry><para>kernel</para></entry> <entry><para>kernel</para></entry>
</row> </row>
</tbody> </tbody>
@ -150,8 +139,8 @@ Timecounter "i8254" frequency 1193182 Hz</screen></para></entry>
so that it points to a BIOS memory block.</para> so that it points to a BIOS memory block.</para>
<para>BIOS stands for <emphasis>Basic Input Output <para>BIOS stands for <emphasis>Basic Input Output
System</emphasis>, and it is a chip on the motherboard that has System</emphasis>, and it is a chip on the motherboard that
a relatively small amount of read-only memory (ROM). This has a relatively small amount of read-only memory (ROM). This
memory contains various low-level routines that are specific to memory contains various low-level routines that are specific to
the hardware supplied with the motherboard. So, the processor the hardware supplied with the motherboard. So, the processor
will first jump to the address 0xfffffff0, which really resides will first jump to the address 0xfffffff0, which really resides
@ -178,8 +167,8 @@ Timecounter "i8254" frequency 1193182 Hz</screen></para></entry>
from 0, but sectors - starting from 1), has a special meaning. from 0, but sectors - starting from 1), has a special meaning.
It is also called Master Boot Record, or MBR. The remaining It is also called Master Boot Record, or MBR. The remaining
sectors on the first track are never used <footnote><para>Some sectors on the first track are never used <footnote><para>Some
utilities such as &man.disklabel.8; may store the information in utilities such as &man.disklabel.8; may store the
this area, mostly in the second information in this area, mostly in the second
sector.</para></footnote>.</para> sector.</para></footnote>.</para>
</sect1> </sect1>
@ -190,7 +179,8 @@ Timecounter "i8254" frequency 1193182 Hz</screen></para></entry>
<para>Take a look at the file <filename>/boot/boot0</filename>. <para>Take a look at the file <filename>/boot/boot0</filename>.
This is a small 512-byte file, and it is exactly what FreeBSD's This is a small 512-byte file, and it is exactly what FreeBSD's
installation procedure wrote to your harddisk's MBR if you chose installation procedure wrote to your harddisk's MBR if you chose
the <quote>bootmanager</quote> option at installation time.</para> the <quote>bootmanager</quote> option at installation
time.</para>
<para>As mentioned previously, the <literal>INT 0x19</literal> <para>As mentioned previously, the <literal>INT 0x19</literal>
instruction loads an MBR, i.e. the <filename>boot0</filename> instruction loads an MBR, i.e. the <filename>boot0</filename>
@ -346,16 +336,21 @@ boot2: boot2.ldr boot2.bin ${BTX}/btx/btx
<indexterm><primary>virtual v86 mode</primary></indexterm> <indexterm><primary>virtual v86 mode</primary></indexterm>
<itemizedlist> <itemizedlist>
<listitem><para>virtual v86 mode. That means, the BTX is a v86 <listitem>
monitor. Real mode instructions like pushf, popf, cli, sti, if <para>virtual v86 mode. That means, the BTX is a v86 monitor.
called by the client, will work.</para></listitem> Real mode instructions like pushf, popf, cli, sti, if called
by the client, will work.</para>
</listitem>
<listitem><para>Interrupt Descriptor Table (IDT) is set up so <listitem>
all hardware interrupts are routed to the default BIOS's <para>Interrupt Descriptor Table (IDT) is set up so all
hardware interrupts are routed to the default BIOS's
handlers, and interrupt 0x30 is set up to be the syscall handlers, and interrupt 0x30 is set up to be the syscall
gate.</para></listitem> gate.</para>
</listitem>
<listitem><para>Two system calls: <function>exec</function> and <listitem>
<para>Two system calls: <function>exec</function> and
<function>exit</function>, are defined:</para> <function>exit</function>, are defined:</para>
<programlisting><filename>sys/boot/i386/btx/lib/btxsys.s:</filename> <programlisting><filename>sys/boot/i386/btx/lib/btxsys.s:</filename>
@ -369,7 +364,8 @@ __exit: xorl %eax,%eax # BTX system
# System call: exec # System call: exec
# #
__exec: movl $0x1,%eax # BTX system __exec: movl $0x1,%eax # BTX system
int $INT_SYS # call 0x1</programlisting></listitem> int $INT_SYS # call 0x1</programlisting>
</listitem>
</itemizedlist> </itemizedlist>
<para>BTX creates a Global Descriptor Table (GDT):</para> <para>BTX creates a Global Descriptor Table (GDT):</para>
@ -438,19 +434,20 @@ struct bootinfo {
u_int32_t bi_modulep; /* preloaded modules */ u_int32_t bi_modulep; /* preloaded modules */
};</programlisting> };</programlisting>
<para><literal>boot2</literal> enters into an infinite loop waiting <para><literal>boot2</literal> enters into an infinite loop
for user input, then calls <function>load()</function>. If the waiting for user input, then calls <function>load()</function>.
user does not press anything, the loop breaks by a timeout, so If the user does not press anything, the loop breaks by a
<function>load()</function> will load the default file timeout, so <function>load()</function> will load the default
(<filename>/boot/loader</filename>). Functions <function>ino_t file (<filename>/boot/loader</filename>). Functions
lookup(char *filename)</function> and <function>int xfsread(ino_t <function>ino_t lookup(char *filename)</function> and
inode, void *buf, size_t nbyte)</function> are used to read the <function>int xfsread(ino_t inode, void *buf, size_t
content of a file into memory. <filename>/boot/loader</filename> nbyte)</function> are used to read the content of a file into
is an ELF binary, but where the ELF header is prepended with memory. <filename>/boot/loader</filename> is an ELF binary, but
a.out's <literal>struct exec</literal> structure. where the ELF header is prepended with a.out's <literal>struct
<function>load()</function> scans the loader's ELF header, loading exec</literal> structure. <function>load()</function> scans the
the content of <filename>/boot/loader</filename> into memory, and loader's ELF header, loading the content of
passing the execution to the loader's entry:</para> <filename>/boot/loader</filename> into memory, and passing the
execution to the loader's entry:</para>
<programlisting><filename>sys/boot/i386/boot2/boot2.c:</filename> <programlisting><filename>sys/boot/i386/boot2/boot2.c:</filename>
__exec((caddr_t)addr, RB_BOOTINFO | (opts &amp; RBX_MASK), __exec((caddr_t)addr, RB_BOOTINFO | (opts &amp; RBX_MASK),
@ -478,10 +475,10 @@ struct bootinfo {
<sect1 id="boot-kernel"> <sect1 id="boot-kernel">
<title>Kernel Initialization</title> <title>Kernel Initialization</title>
<para>Let us take a look at the command that links the kernel. This <para>Let us take a look at the command that links the kernel.
will help identify the exact location where the loader passes This will help identify the exact location where the loader
execution to the kernel. This location is the kernel's actual entry passes execution to the kernel. This location is the kernel's
point.</para> actual entry point.</para>
<programlisting><filename>sys/conf/Makefile.i386:</filename> <programlisting><filename>sys/conf/Makefile.i386:</filename>
ld -elf -Bdynamic -T /usr/src/sys/conf/ldscript.i386 -export-dynamic \ ld -elf -Bdynamic -T /usr/src/sys/conf/ldscript.i386 -export-dynamic \
@ -489,8 +486,8 @@ ld -elf -Bdynamic -T /usr/src/sys/conf/ldscript.i386 -export-dynamic \
&lt;lots of kernel .o files&gt;</programlisting> &lt;lots of kernel .o files&gt;</programlisting>
<indexterm><primary>ELF</primary></indexterm> <indexterm><primary>ELF</primary></indexterm>
<para>A few interesting things can be seen here. First, <para>A few interesting things can be seen here. First, the
the kernel is an ELF dynamically linked binary, but the dynamic kernel is an ELF dynamically linked binary, but the dynamic
linker for kernel is <filename>/red/herring</filename>, which is linker for kernel is <filename>/red/herring</filename>, which is
definitely a bogus file. Second, taking a look at the file definitely a bogus file. Second, taking a look at the file
<filename>sys/conf/ldscript.i386</filename> gives an idea about <filename>sys/conf/ldscript.i386</filename> gives an idea about
@ -513,9 +510,9 @@ ENTRY(btext)</programlisting>
*/ */
NON_GPROF_ENTRY(btext)</programlisting> NON_GPROF_ENTRY(btext)</programlisting>
<para>First, the register EFLAGS is set to a <para>First, the register EFLAGS is set to a predefined value of
predefined value of 0x00000002. Then all the segment 0x00000002. Then all the segment registers are
registers are initialized:</para> initialized:</para>
<programlisting><filename>sys/i386/i386/locore.s:</filename> <programlisting><filename>sys/i386/i386/locore.s:</filename>
/* Don't trust what the BIOS gives for eflags. */ /* Don't trust what the BIOS gives for eflags. */
@ -542,7 +539,6 @@ NON_GPROF_ENTRY(btext)</programlisting>
<tbody> <tbody>
<row> <row>
<entry><function>recover_bootinfo</function></entry> <entry><function>recover_bootinfo</function></entry>
<entry>This routine parses the parameters to the kernel <entry>This routine parses the parameters to the kernel
passed from the bootstrap. The kernel may have been passed from the bootstrap. The kernel may have been
booted in 3 ways: by the loader, described above, by the booted in 3 ways: by the loader, described above, by the
@ -554,7 +550,6 @@ NON_GPROF_ENTRY(btext)</programlisting>
<row> <row>
<entry><function>identify_cpu</function></entry> <entry><function>identify_cpu</function></entry>
<entry>This functions tries to find out what CPU it is <entry>This functions tries to find out what CPU it is
running on, storing the value found in a variable running on, storing the value found in a variable
<varname>_cpu</varname>.</entry> <varname>_cpu</varname>.</entry>
@ -562,7 +557,6 @@ NON_GPROF_ENTRY(btext)</programlisting>
<row> <row>
<entry><function>create_pagetables</function></entry> <entry><function>create_pagetables</function></entry>
<entry>This function allocates and fills out a Page Table <entry>This function allocates and fills out a Page Table
Directory at the top of the kernel memory area.</entry> Directory at the top of the kernel memory area.</entry>
</row> </row>
@ -580,6 +574,7 @@ NON_GPROF_ENTRY(btext)</programlisting>
movl %eax, %cr4</programlisting> movl %eax, %cr4</programlisting>
<para>Then, enabling paging:</para> <para>Then, enabling paging:</para>
<programlisting>/* Now enable paging */ <programlisting>/* Now enable paging */
movl R(_IdlePTD), %eax movl R(_IdlePTD), %eax
movl %eax,%cr3 /* load ptd addr into mmu */ movl %eax,%cr3 /* load ptd addr into mmu */
@ -621,9 +616,9 @@ begin:</programlisting>
low-level initialization specific to the i386 chip. The low-level initialization specific to the i386 chip. The
switch to protected mode was performed by the loader. The switch to protected mode was performed by the loader. The
loader has created the very first task, in which the kernel loader has created the very first task, in which the kernel
continues to operate. Before looking at the continues to operate. Before looking at the code, consider
code, consider the tasks the processor must complete the tasks the processor must complete to initialize protected
to initialize protected mode execution:</para> mode execution:</para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
@ -662,12 +657,11 @@ begin:</programlisting>
</itemizedlist> </itemizedlist>
<indexterm><primary>parameters</primary></indexterm> <indexterm><primary>parameters</primary></indexterm>
<para><function>init386()</function> <para><function>init386()</function> initializes the tunable
initializes the tunable parameters passed from bootstrap parameters passed from bootstrap by setting the environment
by setting the environment pointer (envp) and calling pointer (envp) and calling <function>init_param1()</function>.
<function>init_param1()</function>. The envp pointer has been The envp pointer has been passed from loader in the
passed from loader in the <literal>bootinfo</literal> <literal>bootinfo</literal> structure:</para>
structure:</para>
<programlisting><filename>sys/i386/i386/machdep.c:</filename> <programlisting><filename>sys/i386/i386/machdep.c:</filename>
kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE; kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE;
@ -693,28 +687,28 @@ begin:</programlisting>
#define TUNABLE_INT_FETCH(path, var) getenv_int((path), (var)) #define TUNABLE_INT_FETCH(path, var) getenv_int((path), (var))
</programlisting> </programlisting>
<para>Sysctl <literal>kern.hz</literal> is the system clock tick. <para>Sysctl <literal>kern.hz</literal> is the system clock
Additionally, these sysctls are set by tick. Additionally, these sysctls are set by
<function>init_param1()</function>: <literal>kern.maxswzone, <function>init_param1()</function>: <literal>kern.maxswzone,
kern.maxbcache, kern.maxtsiz, kern.dfldsiz, kern.maxdsiz, kern.dflssiz, kern.maxbcache, kern.maxtsiz, kern.dfldsiz, kern.maxdsiz,
kern.maxssiz, kern.sgrowsiz</literal>.</para> kern.dflssiz, kern.maxssiz, kern.sgrowsiz</literal>.</para>
<indexterm><primary>Global Descriptors Table (GDT)</primary></indexterm> <indexterm><primary>Global Descriptors Table
(GDT)</primary></indexterm>
<para>Then <function>init386()</function> prepares the Global <para>Then <function>init386()</function> prepares the Global
Descriptors Table (GDT). Every task on an x86 is running in Descriptors Table (GDT). Every task on an x86 is running in
its own virtual address space, and this space is addressed by its own virtual address space, and this space is addressed by
a segment:offset pair. Say, for instance, the current a segment:offset pair. Say, for instance, the current
instruction to be executed by the processor lies at CS:EIP, instruction to be executed by the processor lies at CS:EIP,
then the linear virtual address for that instruction would be then the linear virtual address for that instruction would be
<quote>the virtual address of code segment CS</quote> + EIP. For <quote>the virtual address of code segment CS</quote> + EIP.
convenience, segments begin at virtual address 0 and end at a For convenience, segments begin at virtual address 0 and end
4Gb boundary. Therefore, the instruction's linear virtual at a 4Gb boundary. Therefore, the instruction's linear
address for this example would just be the value of EIP. virtual address for this example would just be the value of
Segment registers such as CS, DS etc are the selectors, 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 i.e. indexes, into GDT (to be more precise, an index is not a
selector itself, but the INDEX field of a selector). selector itself, but the INDEX field of a selector). FreeBSD's
FreeBSD's GDT holds descriptors for 15 selectors per GDT holds descriptors for 15 selectors per CPU:</para>
CPU:</para>
<programlisting><filename>sys/i386/i386/machdep.c:</filename> <programlisting><filename>sys/i386/i386/machdep.c:</filename>
union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */
@ -744,11 +738,12 @@ union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */
indices of the GDT. for example, an actual selector for the indices of the GDT. for example, an actual selector for the
kernel code (GCODE_SEL) has the value 0x08.</para> kernel code (GCODE_SEL) has the value 0x08.</para>
<indexterm><primary>Interrupt Descriptor Table (IDT)</primary></indexterm> <indexterm><primary>Interrupt Descriptor Table
(IDT)</primary></indexterm>
<para>The next step is to initialize the Interrupt Descriptor <para>The next step is to initialize the Interrupt Descriptor
Table (IDT). This table is referenced by the processor Table (IDT). This table is referenced by the processor when a
when a software or hardware interrupt occurs. For example, to software or hardware interrupt occurs. For example, to make a
make a system call, user application issues the <literal>INT system call, user application issues the <literal>INT
0x80</literal> instruction. This is a software interrupt, so 0x80</literal> instruction. This is a software interrupt, so
the processor's hardware looks up a record with index 0x80 in the processor's hardware looks up a record with index 0x80 in
the IDT. This record points to the routine that handles this the IDT. This record points to the routine that handles this
@ -812,9 +807,9 @@ struct gate_descriptor *idt = &amp;idt0[0]; /* interrupt descriptor table */
<para>Next, proc0's Process Control Block (<literal>struct <para>Next, proc0's Process Control Block (<literal>struct
pcb</literal>) structure is initialized. proc0 is a pcb</literal>) structure is initialized. proc0 is a
<literal>struct proc</literal> structure that describes a kernel <literal>struct proc</literal> structure that describes a
process. It is always present while the kernel is running, kernel process. It is always present while the kernel is
therefore it is declared as global:</para> running, therefore it is declared as global:</para>
<programlisting><filename>sys/kern/kern_init.c:</filename> <programlisting><filename>sys/kern/kern_init.c:</filename>
struct proc proc0;</programlisting> struct proc proc0;</programlisting>
@ -822,8 +817,8 @@ struct gate_descriptor *idt = &amp;idt0[0]; /* interrupt descriptor table */
<para>The structure <literal>struct pcb</literal> is a part of a <para>The structure <literal>struct pcb</literal> is a part of a
proc structure. It is defined in proc structure. It is defined in
<filename>/usr/include/machine/pcb.h</filename> and has a <filename>/usr/include/machine/pcb.h</filename> and has a
process's information specific to the i386 architecture, such as process's information specific to the i386 architecture, such
registers values.</para> as registers values.</para>
</sect2> </sect2>
<sect2> <sect2>
@ -850,9 +845,9 @@ struct gate_descriptor *idt = &amp;idt0[0]; /* interrupt descriptor table */
<indexterm><primary>sysinit objects</primary></indexterm> <indexterm><primary>sysinit objects</primary></indexterm>
<para>Every system initialization object (sysinit object) is <para>Every system initialization object (sysinit object) is
created by calling a SYSINIT() macro. Let us take as example an created by calling a SYSINIT() macro. Let us take as example
<literal>announce</literal> sysinit object. This object prints an <literal>announce</literal> sysinit object. This object
the copyright message:</para> prints the copyright message:</para>
<programlisting><filename>sys/kern/init_main.c:</filename> <programlisting><filename>sys/kern/init_main.c:</filename>
static void static void
@ -873,6 +868,7 @@ SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright)</p
<literal>C_SYSINIT()</literal> macro then expands to a static <literal>C_SYSINIT()</literal> macro then expands to a static
<literal>struct sysinit</literal> structure declaration with <literal>struct sysinit</literal> structure declaration with
another <literal>DATA_SET</literal> macro call:</para> another <literal>DATA_SET</literal> macro call:</para>
<programlisting><filename>/usr/include/sys/kernel.h:</filename> <programlisting><filename>/usr/include/sys/kernel.h:</filename>
#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \ #define C_SYSINIT(uniquifier, subsystem, order, func, ident) \
static struct sysinit uniquifier ## _sys_init = { \ subsystem, \ static struct sysinit uniquifier ## _sys_init = { \ subsystem, \
@ -884,8 +880,8 @@ SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright)</p
(sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)ident)</programlisting> (sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)ident)</programlisting>
<para>The <literal>DATA_SET()</literal> macro expands to a <para>The <literal>DATA_SET()</literal> macro expands to a
<literal>MAKE_SET()</literal>, and that macro is the point where <literal>MAKE_SET()</literal>, and that macro is the point
the all sysinit magic is hidden:</para> where the all sysinit magic is hidden:</para>
<programlisting><filename>/usr/include/linker_set.h:</filename> <programlisting><filename>/usr/include/linker_set.h:</filename>
#define MAKE_SET(set, sym) \ #define MAKE_SET(set, sym) \
@ -913,15 +909,17 @@ __asm(".long " "announce_sys_init");
__asm(".previous");</programlisting> __asm(".previous");</programlisting>
<para>The first <literal>__asm</literal> instruction will create <para>The first <literal>__asm</literal> instruction will create
an ELF section within the kernel's executable. This will happen an ELF section within the kernel's executable. This will
at kernel link time. The section will have the name happen at kernel link time. The section will have the name
<literal>.set.sysinit_set</literal>. The content of this section is one 32-bit <literal>.set.sysinit_set</literal>. The content of this
value, the address of announce_sys_init structure, and that is section is one 32-bit value, the address of announce_sys_init
what the second <literal>__asm</literal> is. The third structure, and that is what the second
<literal>__asm</literal> instruction marks the end of a section. <literal>__asm</literal> is. The third
If a directive with the same section name occurred before, the <literal>__asm</literal> instruction marks the end of a
content, i.e. the 32-bit value, will be appended to the existing section. If a directive with the same section name occurred
section, so forming an array of 32-bit pointers.</para> before, the content, i.e. the 32-bit value, will be appended
to the existing section, so forming an array of 32-bit
pointers.</para>
<para>Running <application>objdump</application> on a kernel <para>Running <application>objdump</application> on a kernel
binary, you may notice the presence of such small binary, you may notice the presence of such small
@ -943,14 +941,15 @@ __asm(".previous");</programlisting>
<para>This screen dump shows that the size of .set.sysinit_set <para>This screen dump shows that the size of .set.sysinit_set
section is 0x664 bytes, so <literal>0x664/sizeof(void section is 0x664 bytes, so <literal>0x664/sizeof(void
*)</literal> sysinit objects are compiled into the kernel. The *)</literal> sysinit objects are compiled into the kernel.
other sections such as <literal>.set.sysctl_set</literal> The other sections such as <literal>.set.sysctl_set</literal>
represent other linker sets.</para> represent other linker sets.</para>
<para>By defining a variable of type <literal>struct <para>By defining a variable of type <literal>struct
linker_set</literal> the content of linker_set</literal> the content of
<literal>.set.sysinit_set</literal> section will be <quote>collected</quote> <literal>.set.sysinit_set</literal> section will be
into that variable:</para> <quote>collected</quote> into that variable:</para>
<programlisting><filename>sys/kern/init_main.c:</filename> <programlisting><filename>sys/kern/init_main.c:</filename>
extern struct linker_set sysinit_set; /* XXX */</programlisting> extern struct linker_set sysinit_set; /* XXX */</programlisting>
@ -964,14 +963,14 @@ __asm(".previous");</programlisting>
};</programlisting> };</programlisting>
<para>The first node will be equal to the number of a sysinit <para>The first node will be equal to the number of a sysinit
objects, and the second node will be a NULL-terminated array of objects, and the second node will be a NULL-terminated array
pointers to them.</para> of pointers to them.</para>
<para>Returning to the <function>mi_startup()</function> <para>Returning to the <function>mi_startup()</function>
discussion, it is must be clear now, how the sysinit objects are discussion, it is must be clear now, how the sysinit objects
being organized. The <function>mi_startup()</function> function are being organized. The <function>mi_startup()</function>
sorts them and calls each. The very last object is the system function sorts them and calls each. The very last object is
scheduler:</para> the system scheduler:</para>
<programlisting><filename>/usr/include/sys/kernel.h:</filename> <programlisting><filename>/usr/include/sys/kernel.h:</filename>
enum sysinit_sub_id { enum sysinit_sub_id {
@ -985,13 +984,14 @@ enum sysinit_sub_id {
<para>The system scheduler sysinit object is defined in the file <para>The system scheduler sysinit object is defined in the file
<filename>sys/vm/vm_glue.c</filename>, and the entry point for <filename>sys/vm/vm_glue.c</filename>, and the entry point for
that object is <function>scheduler()</function>. That function that object is <function>scheduler()</function>. That
is actually an infinite loop, and it represents a process with function is actually an infinite loop, and it represents a
PID 0, the swapper process. The proc0 structure, mentioned process with PID 0, the swapper process. The proc0 structure,
before, is used to describe it.</para> mentioned before, is used to describe it.</para>
<para>The first user process, called <emphasis>init</emphasis>, is <para>The first user process, called <emphasis>init</emphasis>,
created by the sysinit object <literal>init</literal>:</para> is created by the sysinit object
<literal>init</literal>:</para>
<programlisting><filename>sys/kern/init_main.c:</filename> <programlisting><filename>sys/kern/init_main.c:</filename>
static void static void
@ -1011,11 +1011,12 @@ create_init(const void *udata __unused)
} }
SYSINIT(init,SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL)</programlisting> SYSINIT(init,SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL)</programlisting>
<para>The <function>create_init()</function> allocates a new process <para>The <function>create_init()</function> allocates a new
by calling <function>fork1()</function>, but does not mark it process by calling <function>fork1()</function>, but does not
runnable. When this new process is scheduled for execution by the mark it runnable. When this new process is scheduled for
scheduler, the <function>start_init()</function> will be called. execution by the scheduler, the
That function is defined in <filename>init_main.c</filename>. It <function>start_init()</function> will be called. That
function is defined in <filename>init_main.c</filename>. It
tries to load and exec the <filename>init</filename> binary, tries to load and exec the <filename>init</filename> binary,
probing <filename>/sbin/init</filename> first, then probing <filename>/sbin/init</filename> first, then
<filename>/sbin/oinit</filename>, <filename>/sbin/oinit</filename>,
@ -1029,10 +1030,8 @@ static char init_path[MAXPATHLEN] =
#else #else
"/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall"; "/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall";
#endif</programlisting> #endif</programlisting>
</sect2> </sect2>
</sect1> </sect1>
</chapter> </chapter>
<!-- <!--