From 75e065b0faf049b07c33ec55028865c29bcf9a8a Mon Sep 17 00:00:00 2001 From: Warren Block Date: Tue, 10 Jan 2012 02:50:25 +0000 Subject: [PATCH] Whitespace-only fixes to indentation and line wrap. Translators may ignore. Approved by: gjb (mentor) --- .../books/arch-handbook/boot/chapter.sgml | 577 +++++++++--------- 1 file changed, 288 insertions(+), 289 deletions(-) diff --git a/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml index edd443232d..0ebfdc3aa9 100644 --- a/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml +++ b/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml @@ -10,7 +10,7 @@ $FreeBSD$ - Sergey + Sergey Lyubka Contributed by @@ -64,39 +64,32 @@ $FreeBSD$ - - - Output (may vary) - + + + Output (may vary) BIOS (firmware) messages - + - - -F1 FreeBSD + + F1 FreeBSD F2 BSD -F5 Disk 2 - - +F5 Disk 2 boot0 - + - - ->>FreeBSD/i386 BOOT + + >>FreeBSD/i386 BOOT Default: 1:ad(1,a)/boot/loader -boot: - - +boot: boot2This - prompt will appear if the user presses a key just after - selecting an OS to boot at the boot0 - stage. - + prompt will appear if the user presses a key just + after selecting an OS to boot at the + boot0 + stage. + - - -BTX loader 1.0 BTX version is 1.01 + + BTX loader 1.0 BTX version is 1.01 BIOS drive A: is disk0 BIOS drive C: is disk1 BIOS 639kB/64512kB available memory @@ -105,24 +98,20 @@ Console internal video/keyboard (jkh@bento.freebsd.org, Mon Nov 20 11:41:23 GMT 2000) /kernel text=0x1234 data=0x2345 syms=[0x4+0x3456] Hit [Enter] to boot immediately, or any other key for command prompt -Booting [kernel] in 9 seconds..._ - +Booting [kernel] in 9 seconds..._ + loader + - loader - - - - - Copyright (c) 1992-2002 The FreeBSD Project. + + Copyright (c) 1992-2002 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD 4.6-RC #0: Sat May 4 22:49:02 GMT 2002 devnull@kukas:/usr/obj/usr/src/sys/DEVNULL Timecounter "i8254" frequency 1193182 Hz - - kernel - - + kernel + + @@ -150,8 +139,8 @@ Timecounter "i8254" frequency 1193182 Hz so that it points to a BIOS memory block. BIOS stands for Basic Input Output - System, and it is a chip on the motherboard that has - a relatively small amount of read-only memory (ROM). This + System, and it is a chip on the motherboard that + has a relatively small amount of read-only memory (ROM). This memory contains various low-level routines that are specific to the hardware supplied with the motherboard. So, the processor will first jump to the address 0xfffffff0, which really resides @@ -167,7 +156,7 @@ Timecounter "i8254" frequency 1193182 Hz CD-ROM, harddisk etc. The very last thing in the POST is the INT - 0x19 instruction. That instruction reads 512 bytes + 0x19 instruction. That instruction reads 512 bytes from the first sector of boot device into the memory at address 0x7c00. The term first sector originates from harddrive architecture, where the magnetic plate is divided @@ -178,9 +167,9 @@ Timecounter "i8254" frequency 1193182 Hz from 0, but sectors - starting from 1), has a special meaning. It is also called Master Boot Record, or MBR. The remaining sectors on the first track are never used Some - utilities such as &man.disklabel.8; may store the information in - this area, mostly in the second - sector.. + utilities such as &man.disklabel.8; may store the + information in this area, mostly in the second + sector.. @@ -190,7 +179,8 @@ Timecounter "i8254" frequency 1193182 Hz Take a look at the file /boot/boot0. This is a small 512-byte file, and it is exactly what FreeBSD's installation procedure wrote to your harddisk's MBR if you chose - the bootmanager option at installation time. + the bootmanager option at installation + time. As mentioned previously, the INT 0x19 instruction loads an MBR, i.e. the boot0 @@ -214,19 +204,19 @@ Timecounter "i8254" frequency 1193182 Hz - the 1-byte filesystem type + the 1-byte filesystem type - the 1-byte bootable flag + the 1-byte bootable flag - the 6 byte descriptor in CHS format + the 6 byte descriptor in CHS format - the 8 byte descriptor in LBA format + the 8 byte descriptor in LBA format @@ -346,30 +336,36 @@ boot2: boot2.ldr boot2.bin ${BTX}/btx/btx virtual v86 mode - virtual v86 mode. That means, the BTX is a v86 - monitor. Real mode instructions like pushf, popf, cli, sti, if - called by the client, will work. + + virtual v86 mode. That means, the BTX is a v86 monitor. + Real mode instructions like pushf, popf, cli, sti, if called + by the client, will work. + - 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 - gate. + + 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 + gate. + - Two system calls: exec and - exit, are defined: + + Two system calls: exec and + exit, are defined: - sys/boot/i386/btx/lib/btxsys.s: + sys/boot/i386/btx/lib/btxsys.s: .set INT_SYS,0x30 # Interrupt number # # System call: exit # -__exit: xorl %eax,%eax # BTX system +__exit: xorl %eax,%eax # BTX system int $INT_SYS # call 0x0 # # System call: exec # -__exec: movl $0x1,%eax # BTX system - int $INT_SYS # call 0x1 +__exec: movl $0x1,%eax # BTX system + int $INT_SYS # call 0x1 + BTX creates a Global Descriptor Table (GDT): @@ -392,8 +388,8 @@ gdt: .word 0x0,0x0,0x0,0x0 # Null entry segment pointed to by the SEL_SCODE (supervisor code) selector, as shown from the code that creates an IDT: - mov $SEL_SCODE,%dh # Segment selector -init.2: shr %bx # Handle this int? + mov $SEL_SCODE,%dh # Segment selector +init.2: shr %bx # Handle this int? jnc init.3 # No mov %ax,(%di) # Set handler offset mov %dh,0x2(%di) # and selector @@ -438,21 +434,22 @@ struct bootinfo { u_int32_t bi_modulep; /* preloaded modules */ }; - 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 - (/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. /boot/loader - is an ELF binary, but where the ELF header is prepended with - a.out's struct exec structure. - load() scans the loader's ELF header, loading - the content of /boot/loader into memory, and - passing the execution to the loader's entry: + 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 (/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. /boot/loader is an ELF binary, but + where the ELF header is prepended with a.out's struct + exec structure. load() scans the + loader's ELF header, loading the content of + /boot/loader into memory, and passing the + execution to the loader's entry: - sys/boot/i386/boot2/boot2.c: + sys/boot/i386/boot2/boot2.c: __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), 0, 0, 0, VTOP(&bootinfo)); @@ -470,7 +467,7 @@ struct bootinfo { the kernel is loaded into memory, it is being called by the loader: - sys/boot/common/boot.c: + sys/boot/common/boot.c: /* Call the exec handler from the loader matching the kernel */ module_formats[km->m_loader]->l_exec(km); @@ -478,10 +475,10 @@ struct bootinfo { Kernel Initialization - 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. + 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. sys/conf/Makefile.i386: 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 \ <lots of kernel .o files> ELF - A few interesting things can be seen here. First, - the kernel is an ELF dynamically linked binary, but the dynamic + A few interesting things can be seen here. First, the + kernel is an ELF dynamically linked binary, but the dynamic linker for kernel is /red/herring, which is definitely a bogus file. Second, taking a look at the file sys/conf/ldscript.i386 gives an idea about @@ -498,13 +495,13 @@ ld -elf -Bdynamic -T /usr/src/sys/conf/ldscript.i386 -export-dynamic \ compiling a kernel. Reading through the first few lines, the string - sys/conf/ldscript.i386: + sys/conf/ldscript.i386: ENTRY(btext) says that a kernel's entry point is the symbol `btext'. This symbol is defined in locore.s: - sys/i386/i386/locore.s: + sys/i386/i386/locore.s: .text /********************************************************************** * @@ -513,9 +510,9 @@ ENTRY(btext) */ NON_GPROF_ENTRY(btext) - First, the register EFLAGS is set to a - predefined value of 0x00000002. Then all the segment - registers are initialized: + First, the register EFLAGS is set to a predefined value of + 0x00000002. Then all the segment registers are + initialized: sys/i386/i386/locore.s: /* Don't trust what the BIOS gives for eflags. */ @@ -539,34 +536,31 @@ NON_GPROF_ENTRY(btext) - - - recover_bootinfo + + + recover_bootinfo + This routine parses the parameters to the kernel + passed from the bootstrap. 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. This function determines the booting method, + and stores the struct bootinfo + structure into the kernel memory. + - This routine parses the parameters to the kernel - passed from the bootstrap. 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. This function determines the booting method, - and stores the struct bootinfo - structure into the kernel memory. - + + identify_cpu + This functions tries to find out what CPU it is + running on, storing the value found in a variable + _cpu. + - - identify_cpu - - This functions tries to find out what CPU it is - running on, storing the value found in a variable - _cpu. - - - - create_pagetables - - This function allocates and fills out a Page Table - Directory at the top of the kernel memory area. - - + + create_pagetables + This function allocates and fills out a Page Table + Directory at the top of the kernel memory area. + + @@ -580,6 +574,7 @@ NON_GPROF_ENTRY(btext) movl %eax, %cr4 Then, enabling paging: + /* Now enable paging */ movl R(_IdlePTD), %eax movl %eax,%cr3 /* load ptd addr into mmu */ @@ -617,57 +612,56 @@ begin: <function>init386()</function> init386() is defined in - 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: + 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: - + Initialize the kernel tunable parameters, passed from the bootstrapping program. - + - + Prepare the GDT. - + Prepare the IDT. - + Initialize the system console. - + Initialize the DDB, if it is compiled into kernel. - + Initialize the TSS. - + Prepare the LDT. - + Set up proc0's pcb. - parameters - 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: + parameters + 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: sys/i386/i386/machdep.c: kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE; @@ -676,45 +670,45 @@ begin: init_param1(); init_param1() is defined in - 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(): + 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(): sys/kern/subr_param.c: hz = HZ; TUNABLE_INT_FETCH("kern.hz", &hz); TUNABLE_<typename>_FETCH is used to fetch the value - from the environment: + from the environment: - /usr/src/sys/sys/kernel.h: + /usr/src/sys/sys/kernel.h: #define TUNABLE_INT_FETCH(path, var) getenv_int((path), (var)) - 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. + 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. - Global Descriptors Table (GDT) + Global Descriptors Table + (GDT) 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: + 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: sys/i386/i386/machdep.c: union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ @@ -740,22 +734,23 @@ union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ #define GBIOSARGS_SEL 14 /* BIOS interface (Arguments) */ 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 0x08. + 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 0x08. - Interrupt Descriptor Table (IDT) + Interrupt Descriptor Table + (IDT) 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): + 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): sys/i386/i386/machdep.c: static struct gate_descriptor idt0[NIDT]; @@ -763,18 +758,18 @@ struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ For each interrupt, an appropriate handler is set. The - syscall gate for INT 0x80 is set as - well: + syscall gate for INT 0x80 is set as + well: sys/i386/i386/machdep.c: setidt(0x80, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); 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. + 0x80 instruction, control will transfer to the + function _Xint0x80_syscall, which is in + the kernel code segment and will be executed with supervisor + privileges. Console and DDB are then initialized: DDB @@ -789,13 +784,13 @@ struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ #endif 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. + structure, the TSS is used by the hardware to store task + information when a task switch occurs. 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: + 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: /usr/include/machine/segments.h: #define LSYS5CALLS_SEL 0 /* forced by intel BCS */ @@ -810,28 +805,28 @@ struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ #define NLDT (LBSDICALLS_SEL + 1) - 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 declared as global: + 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 declared as global: - sys/kern/kern_init.c: + sys/kern/kern_init.c: struct proc proc0; - The structure struct pcb is a part of a - proc structure. It is defined in - /usr/include/machine/pcb.h and has a - process's information specific to the i386 architecture, such as - registers values. + The structure struct pcb is a part of a + proc structure. It is defined in + /usr/include/machine/pcb.h and has a + process's information specific to the i386 architecture, such + as registers values. <function>mi_startup()</function> This function performs a bubble sort of all the system - initialization objects and then calls the entry of each object - one by one: + initialization objects and then calls the entry of each object + one by one: sys/kern/init_main.c: for (sipp = sysinit; *sipp; sipp++) { @@ -843,18 +838,18 @@ struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ /* ... skipped ... */ } - Although the sysinit framework is described in the - Developers' + Although the sysinit framework is described in the + Developers' Handbook, I will discuss the internals of it. - sysinit objects - 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: + sysinit objects + 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: - sys/kern/init_main.c: + sys/kern/init_main.c: static void print_caddr_t(void *data __unused) { @@ -862,17 +857,18 @@ print_caddr_t(void *data __unused) } SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright) - The subsystem ID for this object is SI_SUB_COPYRIGHT - (0x0800001), which comes right after the SI_SUB_CONSOLE - (0x0800000). So, the copyright message will be printed out - first, just after the console initialization. + The subsystem ID for this object is SI_SUB_COPYRIGHT + (0x0800001), which comes right after the SI_SUB_CONSOLE + (0x0800000). So, the copyright message will be printed out + first, just after the console initialization. + + 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: - 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: /usr/include/sys/kernel.h: #define C_SYSINIT(uniquifier, subsystem, order, func, ident) \ static struct sysinit uniquifier ## _sys_init = { \ subsystem, \ @@ -883,11 +879,11 @@ SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright)

- The DATA_SET() macro expands to a - MAKE_SET(), and that macro is the point where - the all sysinit magic is hidden: + The DATA_SET() macro expands to a + MAKE_SET(), and that macro is the point + where the all sysinit magic is hidden: - /usr/include/linker_set.h: + /usr/include/linker_set.h: #define MAKE_SET(set, sym) \ static void const * const __set_##set##_sym_##sym = &sym; \ __asm(".section .set." #set ",\"aw\""); \ @@ -897,9 +893,9 @@ SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright)

- In our case, the following declaration will occur: + In our case, the following declaration will occur: - static struct sysinit announce_sys_init = { + static struct sysinit announce_sys_init = { SI_SUB_COPYRIGHT, SI_ORDER_FIRST, (sysinit_cfunc_t)(sysinit_nfunc_t) print_caddr_t, @@ -912,22 +908,24 @@ __asm(".section .set.sysinit_set" ",\"aw\""); __asm(".long " "announce_sys_init"); __asm(".previous"); - The first __asm instruction will create - an ELF section within the kernel's executable. This will happen - at kernel link time. The section will have the name - .set.sysinit_set. The content of this section is one 32-bit - value, the address of announce_sys_init structure, and that is - what the second __asm is. The third - __asm instruction marks the end of a section. - If a directive with the same section name occurred before, the - content, i.e. the 32-bit value, will be appended to the existing - section, so forming an array of 32-bit pointers. + The first __asm instruction will create + an ELF section within the kernel's executable. This will + happen at kernel link time. The section will have the name + .set.sysinit_set. The content of this + section is one 32-bit value, the address of announce_sys_init + structure, and that is what the second + __asm is. The third + __asm instruction marks the end of a + section. If a directive with the same section name occurred + before, the content, i.e. the 32-bit value, will be appended + to the existing section, so forming an array of 32-bit + pointers. - Running objdump on a kernel - binary, you may notice the presence of such small - sections: + Running objdump on a kernel + binary, you may notice the presence of such small + sections: - &prompt.user; objdump -h /kernel + &prompt.user; objdump -h /kernel 7 .set.cons_set 00000014 c03164c0 c03164c0 002154c0 2**2 CONTENTS, ALLOC, LOAD, DATA 8 .set.kbddriver_set 00000010 c03164d4 c03164d4 002154d4 2**2 @@ -941,39 +939,40 @@ __asm(".previous"); 12 .set.sysinit_set 00000664 c0316e90 c0316e90 00215e90 2**2 CONTENTS, ALLOC, LOAD, DATA - This screen dump shows that the size of .set.sysinit_set - section is 0x664 bytes, so 0x664/sizeof(void - *) sysinit objects are compiled into the kernel. The - other sections such as .set.sysctl_set - represent other linker sets. + This screen dump shows that the size of .set.sysinit_set + section is 0x664 bytes, so 0x664/sizeof(void + *) sysinit objects are compiled into the kernel. + The other sections such as .set.sysctl_set + represent other linker sets. + + By defining a variable of type struct + linker_set the content of + .set.sysinit_set section will be + collected into that variable: - By defining a variable of type struct - linker_set the content of - .set.sysinit_set section will be collected - into that variable: sys/kern/init_main.c: extern struct linker_set sysinit_set; /* XXX */ - The struct linker_set is defined as - follows: + The struct linker_set is defined as + follows: - /usr/include/linker_set.h: + /usr/include/linker_set.h: struct linker_set { int ls_length; void *ls_items[1]; /* really ls_length of them, trailing NULL */ }; - The first node will be equal to the number of a sysinit - objects, and the second node will be a NULL-terminated array of - pointers to them. + The first node will be equal to the number of a sysinit + objects, and the second node will be a NULL-terminated array + of pointers to them. - 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: + 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: - /usr/include/sys/kernel.h: + /usr/include/sys/kernel.h: enum sysinit_sub_id { SI_SUB_DUMMY = 0x0000000, /* not executed; for linker*/ SI_SUB_DONE = 0x0000001, /* processed*/ @@ -983,17 +982,18 @@ enum sysinit_sub_id { SI_SUB_RUN_SCHEDULER = 0xfffffff /* scheduler: no return*/ }; - The system scheduler sysinit object is defined in the file - 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 proc0 structure, mentioned - before, is used to describe it. + The system scheduler sysinit object is defined in the file + 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 proc0 structure, + mentioned before, is used to describe it. - The first user process, called init, is - created by the sysinit object init: + The first user process, called init, + is created by the sysinit object + init: - sys/kern/init_main.c: + sys/kern/init_main.c: static void create_init(const void *udata __unused) { @@ -1011,31 +1011,30 @@ create_init(const void *udata __unused) } SYSINIT(init,SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL) - The 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 init_main.c. It - tries to load and exec the init binary, - probing /sbin/init first, then - /sbin/oinit, - /sbin/init.bak, and finally - /stand/sysinstall: + The 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 init_main.c. It + tries to load and exec the init binary, + probing /sbin/init first, then + /sbin/oinit, + /sbin/init.bak, and finally + /stand/sysinstall: - sys/kern/init_main.c: + sys/kern/init_main.c: static char init_path[MAXPATHLEN] = #ifdef INIT_PATH __XSTRING(INIT_PATH); #else "/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall"; #endif - -
-
- + + -