2400 lines
68 KiB
Plaintext
2400 lines
68 KiB
Plaintext
Linux 2.4.x Initialization for IA-32 HOWTO
|
||
Randy Dunlap, rddunlap@ieee.org
|
||
v1.0, 2001-05-17
|
||
|
||
This document contains a description of the Linux 2.4 kernel initial
|
||
ization sequence on IA-32 processors.
|
||
______________________________________________________________________
|
||
|
||
Table of Contents
|
||
|
||
|
||
|
||
Introduction
|
||
|
||
1. Overview
|
||
|
||
2. This document
|
||
|
||
3. Contributions
|
||
|
||
4. Trademarks
|
||
|
||
5. License
|
||
|
||
5. Linux init ("ASCII art")
|
||
|
||
5. Linux early setup
|
||
|
||
6. IA-32 Kernel Setup
|
||
|
||
6.1 start_of_setup:
|
||
6.1.1 Read second hard drive DASD type
|
||
6.1.2 Check that LILO loaded us right
|
||
6.1.3 Check old loader trying to load a big kernel
|
||
6.1.4 Determine system memory size
|
||
6.1.5 Video adapter modes
|
||
6.1.6 Get Hard Disk parameters
|
||
6.1.7 Get Micro Channel bus information
|
||
6.1.8 Check for mouse
|
||
6.1.9 Check for APM BIOS support
|
||
6.1.10 Prepare to move to protected mode
|
||
6.1.11 Enable address line A20
|
||
6.1.12 Make sure any possible coprocessor is properly reset
|
||
6.1.13 Mask all interrupts
|
||
6.1.14 Move to Protected Mode
|
||
6.1.15 Jump to startup_32 code
|
||
|
||
7. Video Setup
|
||
|
||
7.1 video:
|
||
7.1.1 basic_detect:
|
||
7.1.2 mode_params:
|
||
7.1.3 mopar_gr:
|
||
7.1.4 mode_menu:
|
||
7.1.5 mode_set:
|
||
7.1.6 store_screen:
|
||
7.1.7 restore_screen:
|
||
7.1.8 mode_table:
|
||
7.1.9 mode_scan:
|
||
7.1.10 svga_modes:
|
||
7.1.10 Linux architecture-specific initialization
|
||
|
||
8. startup_32:
|
||
|
||
9. Set segment registers to known values
|
||
|
||
10. SMP BSP (Bootstrap Processor) check
|
||
|
||
11. Initialize page tables
|
||
|
||
12. Enable paging
|
||
|
||
13. Clear BSS
|
||
|
||
14. 32-bit setup
|
||
|
||
15. Copy boot parameters and command line out of the way
|
||
|
||
16. checkCPUtype
|
||
|
||
17. Count this processor
|
||
|
||
18. Load descriptor table pointer registers
|
||
|
||
19. Start other processors
|
||
|
||
19. Linux architecture-independent initialization
|
||
|
||
20. start_kernel:
|
||
|
||
20.1 More architecture-specific init
|
||
20.2 Continue architecture-independent init
|
||
20.3 Parsing command line options
|
||
20.4 trap_init
|
||
20.5 init_IRQ
|
||
20.6 sched_init
|
||
20.7 time_init
|
||
20.8 softirq_init
|
||
20.9 console_init
|
||
20.10 init_modules
|
||
20.11 Profiling setup
|
||
20.12 kmem_cache_init
|
||
20.13 sti
|
||
20.14 calibrate_delay
|
||
20.15 INITRD setup
|
||
20.16 mem_init
|
||
20.17 kmem_cache_sizes_init
|
||
20.18 proc_root_init
|
||
20.19 mempages = num_physpages;
|
||
20.20 fork_init(mempages)
|
||
20.21 proc_caches_init()
|
||
20.22 vfs_caches_init(mempages)
|
||
20.23 buffer_init(mempages)
|
||
20.24 page_cache_init(mempages)
|
||
20.25 kiobuf_setup()
|
||
20.26 signals_init()
|
||
20.27 bdev_init()
|
||
20.28 inode_init(mempages)
|
||
20.29 ipc_init()
|
||
20.30 dquot_init_hash()
|
||
20.31 check_bugs()
|
||
20.32 Start other SMP processors (as applicable)
|
||
20.33 Start init thread
|
||
20.34 unlock_kernel()
|
||
20.35 current->need_resched = 1;
|
||
20.36 cpu_idle()
|
||
|
||
21. setup_arch
|
||
|
||
21.1 Copy and convert system parameter data
|
||
21.2 For RAMdisk-enabled configs (CONFIG_BLK_DEV_RAM)
|
||
21.3 setup_memory_region
|
||
21.4 Set memory limits
|
||
21.5 parse_mem_cmdline
|
||
21.6 Setup Page Frames
|
||
21.7 Handle SMP and IO APIC Configurations
|
||
21.8 paging_init()
|
||
21.9 Save the boot-time SMP configuration
|
||
21.10 Reserve INITRD memory
|
||
21.11 Scan for option ROMs
|
||
21.12 Reserve system resources
|
||
|
||
22. init thread
|
||
|
||
23. do_basic_setup {part of the init thread}
|
||
|
||
23.1 Be the reaper of orphaned children
|
||
23.2 MTRRs
|
||
23.3 SYSCTLs
|
||
23.4 Init Many Devices
|
||
23.5 PCI
|
||
23.6 Micro Channel
|
||
23.7 ISA PnP
|
||
23.8 Networking Init
|
||
23.9 Initial RamDisk
|
||
23.10 Start the kernel "context" thread (keventd)
|
||
23.11 Initcalls
|
||
23.12 Filesystems
|
||
23.13 IRDA
|
||
23.14 PCMCIA
|
||
23.15 Mount the root filesystem
|
||
23.16 Mount the dev (device) filesystem
|
||
23.17 Switch to the Initial RamDisk
|
||
23.17 Glossary
|
||
23.17 References
|
||
|
||
|
||
______________________________________________________________________
|
||
|
||
|
||
|
||
1. Introduction
|
||
|
||
|
||
Portions of this text come from comments in the kernel source files
|
||
(obviously). I have added annotations in many places. I hope that
|
||
this will be useful to kernel developers -- either new ones or
|
||
experienced ones who need more of this type of information. However,
|
||
if there's not enough detail here for you, "Use the Source."
|
||
|
||
|
||
1.1. Overview
|
||
|
||
|
||
This description is organized as a brief overview which lists the
|
||
sections that are described later in more detail.
|
||
|
||
The description is in three main sections. The first section covers
|
||
early kernel initialization on IA-32 (but only after your boot loader
|
||
of choice and other intermediate loaders have run; i.e., this
|
||
description does not cover loading the kernel). This section is based
|
||
on the code in "linux/arch/i386/boot/setup.S" and
|
||
"linux/arch/i386/boot/video.S".
|
||
|
||
The second major section covers Linux initialization that is x86- (or
|
||
i386- or IA-32-) specific. This section is based on the source files
|
||
"linux/arch/i386/kernel/head.S" and "linux/arch/i386/kernel/setup.c".
|
||
|
||
The third major section covers Linux initialization that is
|
||
architecture-independent. This section is based on the flow in the
|
||
source file "linux/init/main.c".
|
||
|
||
See the References section for other valuable documents about booting,
|
||
loading, and initialization.
|
||
|
||
|
||
1.2. This document
|
||
|
||
|
||
This document describes Linux 2.4.x initialization on IA-32 (or i386
|
||
or x86) processors -- after one or more kernel boot loaders (if any)
|
||
have done their job.
|
||
|
||
You can format it using the commands (for example):
|
||
|
||
|
||
|
||
% sgml2txt ia32_init_240.sgml
|
||
|
||
|
||
|
||
or
|
||
|
||
|
||
% sgml2html ia32_init_240.sgml
|
||
|
||
|
||
|
||
This will produce plain ASCII or HTML files respectively. You can
|
||
also produce LaTeX, GNU, and RTF info by using the proper sgmltool
|
||
(man sgmltools).
|
||
|
||
|
||
|
||
1.3. Contributions
|
||
|
||
|
||
Additions and corrections are welcome. Please send them to me
|
||
(rddunlap@ieee.org). Contributions of section descriptions that are
|
||
used will be credited to their author(s).
|
||
|
||
|
||
1.4. Trademarks
|
||
|
||
|
||
All trademarks are the property of their respective owners.
|
||
|
||
|
||
1.5. License
|
||
|
||
|
||
Copyright (C) 2001 Randy Dunlap.
|
||
|
||
This document may be distributed only subject to the terms and
|
||
conditions set forth in the LDP (Linux Documentation Project) License
|
||
at "http://www.linuxdoc.org/COPYRIGHT.html".
|
||
|
||
|
||
|
||
2. Linux init ("ASCII art")
|
||
|
||
|
||
Pictorially (loosely speaking :), Linux initialization looks like
|
||
this, where "[...]" means optional (depends on the kernel's
|
||
configuration) and "{...}" is a comment.
|
||
|
||
|
||
|
||
+-------------------------------+
|
||
| arch/i386/boot/setup.S:: + |
|
||
| arch/i386/boot/video.S:: |
|
||
|-------------------------------|
|
||
| start_of_setup: |
|
||
| check that loaded OK |
|
||
| get system memory size |
|
||
| get video mode(s) |
|
||
| get hard disk parameters |
|
||
| get MC bus information |
|
||
| get mouse information |
|
||
| get APM BIOS information |
|
||
| enable address line A20 |
|
||
| reset coprocessor |
|
||
| mask all interrupts |
|
||
| move to protected mode |
|
||
| jmp to startup_32 |
|
||
+-------------------------------+
|
||
|
|
||
v
|
||
+-------------------------------+
|
||
| arch/i386/kernel/head.S:: |
|
||
|-------------------------------|
|
||
| startup_32: |
|
||
| set segment registers to |
|
||
| known values |
|
||
| init basic page tables |
|
||
| setup the stack pointer |
|
||
| clear kernel BSS |
|
||
| setup the IDT |
|
||
| checkCPUtype |
|
||
| load GDT, IDT, and LDT |
|
||
| pointer registers |
|
||
| start_kernel |
|
||
| {it does not return} |
|
||
+-------------------------------+
|
||
|
|
||
v
|
||
+-------------------------------+ +-------------------------------+
|
||
| init/main.c:: | +->| arch/i386/kernel/setup.c:: |
|
||
|-------------------------------| | |-------------------------------|
|
||
| start_kernel(): | | | setup_arch(): |
|
||
| lock_kernel | | | copy boot parameters |
|
||
| setup_arch |--+ | init ramdisk |
|
||
| parse_options |<-+ | setup_memory_region |
|
||
| trap_init | | | parse_cmd_line |
|
||
| cpu_init | | | use the BIOS memory map to |
|
||
| init_IRQ | | | setup page frame info. |
|
||
| sched_init | | | reserve physical page 0 |
|
||
| init_timervecs | | | [find_smp_config] |
|
||
| time_init | | | paging_init |
|
||
| softirq_init | | | [get_smp_config] |
|
||
| console_init | | | [init_apic_mappings] |
|
||
| [init_modules] | | | [reserve INITRD memory] |
|
||
| [profiling setup] | | | probe_roms to search |
|
||
| kmem_cache_init | | | for option ROMs |
|
||
| sti | | | request_resource to |
|
||
| calibrate_delay | | | reserve video RAM memory |
|
||
| [INITRD setup] | | | request_resource to |
|
||
| mem_init | | | reserve all standard PC |
|
||
| free_all_bootmem | +--| I/O system board resources|
|
||
| kmem_cache_sizes_init | +-------------------------------+
|
||
| [proc_root_init] |
|
||
| fork_init |
|
||
| proc_caches_init |
|
||
| vfs_caches_init |
|
||
| buffer_init |
|
||
| page_cache_init |
|
||
| kiobuf_setup |
|
||
| signals_init | +-------------------------------+
|
||
| bdev_init | | init/main.c:: |
|
||
| inode_init | | init(): {...init thread...} |
|
||
| [ipc_init] | | do_basic_setup |
|
||
| [dquot_init_hash] | | {bus/dev init & initcalls}|
|
||
| check_bugs | | free_initmem |
|
||
| [smp_init] {*below} | | open /dev/console |
|
||
| start init thread {---->} |.....| exec init script or shell |
|
||
| unlock_kernel | | or panic |
|
||
| cpu_idle | +-------------------------------+
|
||
+-------------------------------+
|
||
|
||
|
||
+-------------------------------+
|
||
| smpboot.c::smp_init |
|
||
|-------------------------------|
|
||
| arch/i386/kernel/smpboot.c:: |
|
||
| smp_boot_cpus(): |
|
||
| [mtrr_init_boot_cpu] |
|
||
| smp_store_cpu_info |
|
||
| print_cpu_info |
|
||
| save CPU ID/APIC ID mappings|
|
||
| verify_local_APIC |
|
||
| connect_bsp_APIC |
|
||
| setup_local_APIC |
|
||
| foreach valid APIC ID |
|
||
| do_boot_cpu(apicid) |
|
||
| setup_IO_APIC |
|
||
| setup_APIC_clocks |
|
||
| synchronize_tsc_bp |
|
||
+-------------------------------+
|
||
|
||
|
||
|
||
3. Linux early setup
|
||
|
||
|
||
(from linux/arch/i386/boot/setup.S and linux/arch/i386/boot/video.S)
|
||
|
||
NOTE: Register notation is %regname and constant notation is a
|
||
number, with or without a leading '$' sign.
|
||
|
||
|
||
3.1. IA-32 Kernel Setup
|
||
|
||
|
||
"setup.S" is responsible for getting the system data from the BIOS and
|
||
putting them into the appropriate places in system memory.
|
||
|
||
Both "setup.S" and the kernel have been loaded by the boot block.
|
||
|
||
"setup.S" is assembled as 16-bit real-mode code. It switches the
|
||
processor to 32-bit protected mode and jumps to the 32-bit kernel
|
||
code.
|
||
|
||
This code asks the BIOS for memory/disk/other parameters, and puts
|
||
them in a "safe" place: 0x90000-0x901FF, that is, where the boot block
|
||
used to be. It is then up to the protected mode system to read them
|
||
from there before the area is overwritten for buffer-blocks.
|
||
|
||
The "setup.S" code begins with a jmp instruction around the "setup
|
||
header", which must begin at location %cs:2.
|
||
|
||
This is the setup header:
|
||
|
||
|
||
|
||
______________________________________________________________________
|
||
.ascii "HdrS" # header signature
|
||
.word 0x0202 # header version number
|
||
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
|
||
start_sys_seg: .word SYSSEG
|
||
.word kernel_version # pointer to kernel version string
|
||
type_of_loader: .byte 0
|
||
loadflags:
|
||
LOADED_HIGH = 1 # If set, the kernel is loaded high
|
||
#ifndef __BIG_KERNEL__
|
||
.byte 0
|
||
#else
|
||
.byte LOADED_HIGH
|
||
#endif
|
||
setup_move_size: .word 0x8000 # size to move, when setup is not
|
||
# loaded at 0x90000.
|
||
code32_start: # here loaders can put a different
|
||
# start address for 32-bit code.
|
||
#ifndef __BIG_KERNEL__
|
||
.long 0x1000 # default for zImage
|
||
#else
|
||
.long 0x100000# default for big kernel
|
||
#endif
|
||
ramdisk_image: .long 0 # address of loaded ramdisk image
|
||
ramdisk_size: .long 0 # its size in bytes
|
||
bootsect_kludge: .word bootsect_helper, SETUPSEG
|
||
heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
|
||
# space from here (exclusive) down to
|
||
# end of setup code can be used by setup
|
||
# for local heap purposes.
|
||
pad1: .word 0
|
||
cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
|
||
# If nonzero, a 32-bit pointer
|
||
# to the kernel command line.
|
||
trampoline: call start_of_setup # no return from start_of_setup
|
||
.space 1024
|
||
# End of setup header #####################################################
|
||
______________________________________________________________________
|
||
|
||
|
||
|
||
3.1.1. start_of_setup:
|
||
|
||
|
||
|
||
3.1.1.1. Read second hard drive DASD type
|
||
|
||
|
||
Read the DASD type of the second hard drive (BIOS int. 0x13,
|
||
%ax=0x1500, %dl=0x81).
|
||
|
||
# Bootlin depends on this being done early. [TBD:why?]
|
||
|
||
|
||
3.1.1.2. Check that LILO loaded us right
|
||
|
||
|
||
Check the signature words at the end of setup. Signature words are
|
||
used to ensure that LILO loaded us right. If the two words are not
|
||
found correctly, copy the setup sectors and check for the signature
|
||
words again. If they still aren't found, panic("No setup signature
|
||
found ...").
|
||
|
||
|
||
3.1.1.3. Check old loader trying to load a big kernel
|
||
|
||
|
||
If the kernel image is "big" (and hence is "loaded high"), then if the
|
||
loader cannot handle "loaded high" images, then panic ("Wrong loader,
|
||
giving up...").
|
||
|
||
|
||
|
||
3.1.1.4. Determine system memory size
|
||
|
||
|
||
Get the extended memory size {above 1 MB} in KB. First clear the
|
||
extended memory size to 0.
|
||
|
||
#ifndef STANDARD_MEMORY_BIOS_CALL
|
||
|
||
Clear the E820 memory area counter.
|
||
|
||
Try three different memory detection schemes.
|
||
First, try E820h, which lets us assemble a memory map, then try E801h,
|
||
which returns a 32-bit memory size, and finally 88h, which returns
|
||
0-64 MB.
|
||
|
||
Method E820H populates a table in the empty_zero_block that contains a
|
||
list of usable address/size/type tuples. In
|
||
"linux/arch/i386/kernel/setup.c", this information is transferred into
|
||
the e820map, and in "linux/arch/i386/mm/init.c", that new information
|
||
is used to mark pages reserved or not.
|
||
|
||
Method E820H:
|
||
Get the BIOS memory map. E820h returns memory classified into
|
||
different types and allows memory holes. We scan through this memory
|
||
map and build a list of the first 32 memory areas {up to 32 entries or
|
||
BIOS says that there are no more entries}, which we return at
|
||
"E820MAP". [See URL:
|
||
http://www.teleport.com/ acpi/acpihtml/topic245.htm]
|
||
|
||
Method E801H:
|
||
We store the 0xe801 memory size in a completely different place,
|
||
because it will most likely be longer than 16 bits.
|
||
|
||
This is the sum of 2 registers, normalized to 1 KB chunk sizes: %ecx =
|
||
memory size from 1 MB to 16 MB range, in 1 KB chunks + %edx = memory
|
||
size above 16 MB, in 64 KB chunks.
|
||
|
||
Ye Olde Traditional Methode:
|
||
BIOS int. 0x15/AH=0x88 returns the memory size (up to 16 MB or 64 MB,
|
||
depending on the BIOS). We always use this method, regardless of the
|
||
results of the other two methods.
|
||
|
||
#endif
|
||
|
||
Set the keyboard repeat rate to the maximum rate using using BIOS int.
|
||
0x16.
|
||
|
||
|
||
3.1.1.5. Video adapter modes
|
||
|
||
|
||
Find the video adapter and its supported modes and allow the user to
|
||
browse video modes.
|
||
|
||
call video # {see Video section below}
|
||
|
||
|
||
3.1.1.6. Get Hard Disk parameters
|
||
|
||
|
||
Get hd0 data: Save the hd0 descriptor (from int. vector 0x41) at
|
||
INITSEG:0x80 length 0x10.
|
||
|
||
Get hd1 data: Save the hd1 descriptor (from int. vector 0x46) at
|
||
INITSEG:0x90 length 0x10.
|
||
|
||
Check that there IS an hd1, using BIOS int. 0x13. If not, clear its
|
||
descriptor.
|
||
|
||
|
||
3.1.1.7. Get Micro Channel bus information
|
||
|
||
|
||
Check for Micro Channel (MCA) bus:
|
||
|
||
· Set MCA feature table length to 0 in case not found.
|
||
|
||
· Get System Configuration Parameters (BIOS int. 0x15/%ah=0xc0).
|
||
This sets %es:%bx to point to the system feature table.
|
||
|
||
· We keep only the first 16 bytes of the system feature table if
|
||
found: Structure size, Model byte, Submodel byte, BIOS revision,
|
||
and Feature information bytes 1-5. Bit 0 or 1 (either one) of
|
||
Feature byte 1 indicates that the system contains a Micro Channel
|
||
bus.
|
||
|
||
|
||
3.1.1.8. Check for mouse
|
||
|
||
|
||
Check for PS/2 pointing device by using BIOS int. 0x11 {get equipment
|
||
list}.
|
||
|
||
· Clear the pointing device flag (default).
|
||
|
||
· BIOS int. 0x11: get equipment list.
|
||
|
||
· If bit 2 (value 0x04) is set, then a mouse is installed and the
|
||
pointing device flag is set to indicate that the device is present.
|
||
|
||
|
||
3.1.1.9. Check for APM BIOS support
|
||
|
||
|
||
Check for an APM BIOS (if kernel is configured for APM support):
|
||
|
||
· start: clear version field to 0, which means no APM BIOS present.
|
||
|
||
· Check for APM BIOS installation using BIOS int. 0x15.
|
||
|
||
· If not present, done.
|
||
|
||
· Check for "PM" signature returned in %bx.
|
||
|
||
· If no signature, then no APM BIOS: done.
|
||
|
||
· Check for 32-bit support in %cx.
|
||
|
||
· If no 32-bit support, no (good) APM BIOS: done. Must have 32-bit
|
||
APM BIOS support to be used by Linux.
|
||
|
||
· Save the BIOS code segment, BIOS entry point offset, BIOS 16-bit
|
||
code segment, BIOS data segment, BIOS code segment length, and BIOS
|
||
data segment length.
|
||
|
||
· Record the APM BIOS version and flags.
|
||
|
||
|
||
3.1.1.10. Prepare to move to protected mode
|
||
|
||
|
||
We build a jump instruction to the kernel's code32_start address.
|
||
(The loader may have changed it.)
|
||
|
||
Move the kernel to its correct place if necessary.
|
||
|
||
Load the segment descriptors (load %ds = %cs).
|
||
|
||
Make sure that we are at the right position in memory, to accommodate
|
||
the command line and boot parameters at their fixed locations.
|
||
|
||
Load the IDT pointer register with 0,0.
|
||
|
||
Calculate the linear base address of the kernel GDT (table) and load
|
||
the GDT pointer register with its base address and limit. This early
|
||
kernel GDT describes kernel code as 4 GB, with base address 0,
|
||
code/readable/executable, with granularity of 4 KB. The kernel data
|
||
segment is described as 4 GB, with base address 0,
|
||
data/readable/writable, with granularity of 4 KB.
|
||
|
||
|
||
3.1.1.11. Enable address line A20
|
||
|
||
|
||
|
||
· Empty the 8042 (keyboard controller) of any queued keys.
|
||
|
||
· Write 0xd1 (Write Output Port) to Command Register port 0x64.
|
||
|
||
· Empty the 8042 (keyboard controller) of any queued keys.
|
||
|
||
· Write 0xdf (Gate A20 + more) to Output port 0x60.
|
||
|
||
· Empty the 8042 (keyboard controller) of any queued keys.
|
||
|
||
· Set bit number 1 (value 0x02: FAST_A20) in the "port 0x92" system
|
||
control register. This enables A20 on some systems, depending on
|
||
the chipset used in them.
|
||
|
||
· Wait until A20 really *is* enabled; it can take a fair amount of
|
||
time on certain systems. The memory location used here (0x200) is
|
||
the int 0x80 vector, which should be safe to use. When A20 is
|
||
disabled, the test memory locations are an alias of each other
|
||
(segment 0:offset 0x200 and segment 0xffff:offset 0x210). {0xffff0
|
||
+ 0x210 = 0x100200, but if A20 is disabled, this becomes 0x000200.}
|
||
We just wait (busy wait/loop) until these memory locations are no
|
||
longer aliased.
|
||
|
||
|
||
3.1.1.12. Make sure any possible coprocessor is properly reset
|
||
|
||
|
||
|
||
· Write 0 to port 0xf0 to clear the Math Coprocessor '-busy' signal.
|
||
|
||
· Write 0 to port 0xf1 to reset the Math Coprocessor.
|
||
|
||
|
||
|
||
3.1.1.13. Mask all interrupts
|
||
|
||
|
||
Now we mask all interrupts; the rest is done in init_IRQ().
|
||
|
||
|
||
· Mask off all interrupts on the slave PIC: write 0xff to port 0xa1.
|
||
|
||
· Mask off all interrupts on the master PIC except for IRQ2, which is
|
||
the cascaded IRQ input from the slave PIC: write 0xfb to port 0x21.
|
||
|
||
|
||
3.1.1.14. Move to Protected Mode
|
||
|
||
|
||
Now is the time to actually move into protected mode. To make things
|
||
as simple as possible, we do no register setup or anything, we let the
|
||
GNU-compiled 32-bit programs do that. We just jump to absolute
|
||
address 0x1000 (or the loader supplied one), in 32-bit protected mode.
|
||
|
||
Note that the short jump isn't strictly needed, although there are
|
||
reasons why it might be a good idea. It won't hurt in any case.
|
||
|
||
Set the PE (Protected mode Enable) bit in the MSW and jump to the
|
||
following instruction to flush the instruction fetch queue.
|
||
|
||
Clear %bx to indicate that this is the BSP (first CPU only).
|
||
|
||
|
||
3.1.1.15. Jump to startup_32 code
|
||
|
||
|
||
Jump to the 32-bit kernel code (startup_32).
|
||
|
||
NOTE: For high-loaded big kernels we need:
|
||
|
||
|
||
jmpi 0x100000,__KERNEL_CS
|
||
|
||
|
||
|
||
but we yet haven't reloaded the %cs register, so the default size of
|
||
the target offset still is 16 bit. However, using an operand prefix
|
||
(0x66), the CPU will properly take our 48-bit far pointer. (INTeL
|
||
80386 Programmer's Reference Manual, Mixing 16-bit and 32-bit code,
|
||
page 16-6).
|
||
|
||
|
||
|
||
.byte 0x66, 0xea # prefix + jmpi-opcode
|
||
code32: .long 0x1000 # or 0x100000 for big kernels
|
||
.word __KERNEL_CS
|
||
|
||
|
||
|
||
This jumps to "startup_32" in "linux/arch/i386/kernel/head.S".
|
||
|
||
|
||
3.2. Video Setup
|
||
|
||
|
||
"linux/arch/i386/boot/video.S" is included into
|
||
"linux/arch/i386/boot/setup.S", so they are assembled together. The
|
||
file separation is a logical module separation even though the two
|
||
modules aren't built separately.
|
||
|
||
"video.S" handles Linux/i386 display adapter and video mode setup.
|
||
For more information about Linux/i386 video modes, see
|
||
"linux/Documentation/svga.txt" by Martin Mares [mj@ucw.cz].
|
||
|
||
Video mode selection is a kernel build option. When it is enabled,
|
||
You can select a specific (fixed) video mode to be used during kernel
|
||
booting or you can ask to view a selection menu and then choose a
|
||
video mode from that menu.
|
||
|
||
There are a few esoteric (!) "video.S" build options that not covered
|
||
here. See "linux/Documentation/svga.txt" for all of them.
|
||
|
||
CONFIG_VIDEO_SVGA (for automatic detection of SVGA adapters and modes)
|
||
is normally #undefined. The normal method of video adapter detection
|
||
on Linux/i386 is VESA (CONFIG_VIDEO_VESA, for autodetection of VESA
|
||
modes).
|
||
|
||
"video:" is the main entry point called by "setup.S". The %ds
|
||
register *must* be pointing to the bootsector. The "video.S" code
|
||
uses different segments from the main "setup.S" code.
|
||
|
||
This is a simplified description of the code flow in "video.S". It
|
||
does not address the CONFIG_VIDEO_LOCAL, CONFIG_VIDEO_400_HACK, and
|
||
CONFIG_VIDEO_GFX_HACK build options and it does not dive deep into
|
||
video BIOS calls or video register accesses.
|
||
|
||
|
||
3.2.1. video:
|
||
|
||
|
||
|
||
· %fs is set to the original %ds value
|
||
|
||
· %ds and %es are set to %cs
|
||
|
||
· %gs is set to zero
|
||
|
||
· Detect the video adapter type and supported modes. (call
|
||
basic_detect)
|
||
|
||
· #ifdef CONFIG_VIDEO_SELECT
|
||
|
||
· If the user wants to see a list of the supported VGA adapter modes,
|
||
list them. (call mode_menu)
|
||
|
||
· Set the selected video mode. (call mode_set)
|
||
|
||
· #ifdef CONFIG_VIDEO_RETAIN
|
||
|
||
· Restore the screen contents. (call restore_screen)
|
||
|
||
· #endif /* CONFIG_VIDEO_RETAIN */
|
||
|
||
· #endif /* CONFIG_VIDEO_SELECT */
|
||
|
||
· Store mode parameters for kernel. (call mode_params)
|
||
|
||
· Restore original DS register value.
|
||
|
||
|
||
3.2.1.1. basic_detect:
|
||
|
||
|
||
|
||
· Detect if we have CGA, MDA, HGA, EGA, or VGA and pass it to the
|
||
kernel.
|
||
|
||
· Check for EGA/VGA using BIOS int. 0x10 calls. This also tells
|
||
whether the video adapter is CGA/MDA/HGA.
|
||
|
||
· The "adapter" variable is returned as 0 for CGA/MDA/HGA, 1 for EGA,
|
||
and 2 for VGA.
|
||
|
||
|
||
3.2.1.2. mode_params:
|
||
|
||
|
||
|
||
· Store the video mode parameters for later use by the kernel. This
|
||
is done by asking the BIOS for mode parameters except for the
|
||
rows/columns parameters in the default 80x25 mode -- these are set
|
||
directly, because some very obscure BIOSes supply insane values.
|
||
|
||
· #ifdef CONFIG_VIDEO_SELECT
|
||
|
||
· For graphics mode with a linear frame buffer, goto mopar_gr.
|
||
|
||
· #endif /* CONFIG_VIDEO_SELECT */
|
||
|
||
· For MDA/CGA/HGA/EGA/VGA:
|
||
|
||
· Read and save cursor position.
|
||
|
||
· Read and save video page/mode/width.
|
||
|
||
· For MDA/HGA, change the video_segment to $0xb000. (Leave it at its
|
||
initial value of $0xb800 for all other adapters.)
|
||
|
||
· Get the Font size (valid only on EGA/VGA).
|
||
|
||
· Save the number of video columns and lines.
|
||
|
||
#ifdef CONFIG_VIDEO_SELECT
|
||
|
||
|
||
3.2.1.3. mopar_gr:
|
||
|
||
|
||
|
||
· Get VESA frame buffer parameters.
|
||
|
||
· Get video mem size and protected mode interface information using
|
||
BIOS int. 0x10 calls.
|
||
|
||
|
||
3.2.1.4. mode_menu:
|
||
|
||
|
||
Build the mode list table and display the mode menu.
|
||
|
||
|
||
3.2.1.5. mode_set:
|
||
|
||
|
||
For the selected video mode, use BIOS int. 0x10 calls or register
|
||
writes as needed to set some or all of:
|
||
|
||
· Reset the video mode
|
||
|
||
|
||
· Number of scan lines
|
||
|
||
· Font pixel size
|
||
|
||
· Save the screen size in force_size. "force_size" is used to
|
||
override possibly broken video BIOS interfaces and is used instead
|
||
of the BIOS variables.
|
||
|
||
Some video modes require register writes to set:
|
||
|
||
· Location of the cursor scan lines
|
||
|
||
· Vertical sync start
|
||
|
||
· Vertical sync end
|
||
|
||
· Vertical display end
|
||
|
||
· Vertical blank start
|
||
|
||
· Vertical blank end
|
||
|
||
· Vertical total
|
||
|
||
· (Vertical) overflow
|
||
|
||
· Correct sync polarity
|
||
|
||
· Preserve clock select bits and color bit
|
||
|
||
{end of mode_set}
|
||
|
||
#ifdef CONFIG_VIDEO_RETAIN /* Normally _IS_ #defined */
|
||
|
||
|
||
3.2.1.6. store_screen:
|
||
|
||
|
||
CONFIG_VIDEO_RETAIN is used to retain screen contents when switching
|
||
modes. This option stores the screen contents to a temporary memory
|
||
buffer (if there is enough memory) so that they can be restored later.
|
||
|
||
|
||
· Save the current number of video lines and columns, cursor
|
||
position, and video mode.
|
||
|
||
· Calculate the image size.
|
||
|
||
· Save the screen image.
|
||
|
||
· Set the "do_restore" flag so that the screen contents will be
|
||
restored at the end of video mode detection/selection.
|
||
|
||
|
||
3.2.1.7. restore_screen:
|
||
|
||
|
||
Restores screen contents from temporary buffer (if already saved).
|
||
|
||
|
||
· Get parameters of current mode.
|
||
|
||
· Set cursor position.
|
||
|
||
· Restore the screen contents.
|
||
|
||
#endif /* CONFIG_VIDEO_RETAIN */
|
||
|
||
|
||
3.2.1.8. mode_table:
|
||
|
||
|
||
Build the table of video modes at `modelist'.
|
||
|
||
|
||
· Store standard modes.
|
||
|
||
· Add modes for standard VGA.
|
||
|
||
· #ifdef CONFIG_VIDEO_LOCAL
|
||
|
||
· Add locally-defined video modes. (call local_modes)
|
||
|
||
· #endif /* CONFIG_VIDEO_LOCAL */
|
||
|
||
· #ifdef CONFIG_VIDEO_VESA
|
||
|
||
· Auto-detect VESA VGA modes. (call vesa_modes)
|
||
|
||
· #endif /* CONFIG_VIDEO_VESA */
|
||
|
||
· #ifdef CONFIG_VIDEO_SVGA
|
||
|
||
· Detect SVGA cards & modes. (call svga_modes)
|
||
|
||
· #endif /* CONFIG_VIDEO_SVGA */
|
||
|
||
· #ifdef CONFIG_VIDEO_COMPACT
|
||
|
||
· Compact the video modes list, removing duplicate entries.
|
||
|
||
· #endif /* CONFIG_VIDEO_COMPACT */
|
||
|
||
|
||
3.2.1.9. mode_scan:
|
||
|
||
|
||
Scans for video modes.
|
||
|
||
|
||
· Start with mode 0.
|
||
|
||
· Test the mode.
|
||
|
||
· Test if it's a text mode.
|
||
|
||
· OK, store the mode.
|
||
|
||
· Restore back to mode 3.
|
||
|
||
#ifdef CONFIG_VIDEO_SVGA
|
||
|
||
|
||
3.2.1.10. svga_modes:
|
||
|
||
|
||
Try to detect the type of SVGA card and supply (usually approximate)
|
||
video mode table for it.
|
||
|
||
|
||
· Test all known SVGA adapters.
|
||
|
||
· Call the test routine for each adapter.
|
||
|
||
· If adapter is found, copy the video modes.
|
||
|
||
· Store pointer to card name.
|
||
|
||
#endif /* CONFIG_VIDEO_SVGA */
|
||
|
||
#endif /* CONFIG_VIDEO_SELECT */
|
||
|
||
|
||
|
||
4. Linux architecture-specific initialization
|
||
|
||
|
||
(from "linux/arch/i386/kernel/head.S")
|
||
|
||
The boot code in "linux/arch/i386/boot/setup.S" transfers execution to
|
||
the beginning code in "linux/arch/i386/kernel/head.S" (labeled
|
||
"startup_32:").
|
||
|
||
To get to this point, a small uncompressed kernel function
|
||
decompresses the remaining compressed kernel image and then it jumps
|
||
to the new kernel code.
|
||
|
||
This is a description of what the "head.S" code does.
|
||
|
||
|
||
4.1. startup_32:
|
||
|
||
|
||
swapper_pg_dir is the top-level page directory, address 0x00101000.
|
||
|
||
On entry, %esi points to the real-mode code as a 32-bit pointer.
|
||
|
||
|
||
4.2. Set segment registers to known values
|
||
|
||
|
||
Set the %ds, %es, %fs, and %gs registers to __KERNEL_DS.
|
||
|
||
|
||
4.3. SMP BSP (Bootstrap Processor) check
|
||
|
||
|
||
#ifdef CONFIG_SMP
|
||
|
||
If %bx is zero, this is a boot on the Bootstrap Processor (BSP), so
|
||
skip this. Otherwise, for an AP (Application Processor):
|
||
|
||
If the desired %cr4 setting is non-zero, turn on the paging options
|
||
(PSE, PAE, ...) and skip "Initialize page tables" (jump to "Enable
|
||
paging").
|
||
|
||
#endif /* CONFIG_SMP */
|
||
|
||
|
||
4.4. Initialize page tables
|
||
|
||
|
||
Begin at pg0 (page 0) and init all pages to 007 (PRESENT + RW + USER).
|
||
|
||
|
||
4.5. Enable paging
|
||
|
||
|
||
Set %cr3 (page table pointer) to swapper_pg_dir.
|
||
|
||
Set the paging ("PG") bit of %cr0 to
|
||
********** enable paging **********.
|
||
|
||
Jump $ to flush the prefetch queue.
|
||
|
||
Jump *[$] to make sure that %eip is relocated.
|
||
|
||
Setup the stack pointer (lss stack_start, %esp).
|
||
|
||
|
||
#ifdef CONFIG_SMP
|
||
|
||
If this is not the BSP (Bootstrap Processor), clear all flags bits and
|
||
jump to checkCPUtype.
|
||
|
||
#endif /* CONFIG_SMP */
|
||
|
||
|
||
4.6. Clear BSS
|
||
|
||
|
||
The BSP clears all of BSS (area between __bss_start and _end) for the
|
||
kernel.
|
||
|
||
|
||
4.7. 32-bit setup
|
||
|
||
|
||
Setup the IDT for 32-bit mode (call setup_idt). setup_idt sets up an
|
||
IDT with 256 entries pointing to the default interrupt handler
|
||
"ignore_int" as interrupt gates. It doesn't actually load the IDT;
|
||
that can be done only after paging has been enabled and the kernel
|
||
moved to PAGE_OFFSET. Interrupts are enabled elsewhere, when we can
|
||
be relatively sure everything is OK.
|
||
|
||
Clear the eflags register (before switching to protected mode).
|
||
|
||
|
||
4.8. Copy boot parameters and command line out of the way
|
||
|
||
|
||
First 2 KB of _empty_zero_page is for boot parameters, second 2 KB is
|
||
for the command line.
|
||
|
||
|
||
4.9. checkCPUtype
|
||
|
||
|
||
Initialize X86_CPUID to -1.
|
||
|
||
Use Flags register, push/pop results, and CPUID instruction(s) to
|
||
determine CPU type and vendor: Sets X86, X86_CPUID, X86_MODEL,
|
||
X86_MASK, and X86_CAPABILITY. Sets bits in %cr0 accordingly.
|
||
|
||
Also checks for presence of an 80287 or 80387 coprocessor. Sets
|
||
X86_HARD_MATH if a math coprocessor or floating point unit is found.
|
||
|
||
|
||
4.10. Count this processor
|
||
|
||
|
||
For CONFIG_SMP builds, increment the "ready" counter to keep a tally
|
||
of the number of CPUs that have been initialized.
|
||
|
||
|
||
4.11. Load descriptor table pointer registers
|
||
|
||
|
||
Load GDT with gdt_descr and IDT with idt_descr. The GDT contains 2
|
||
entries for the kernel (4 GB each for code and data, beginning at 0)
|
||
and 2 userspace entries (4 GB each for code and data, beginning at 0).
|
||
There are 2 null descriptors between the userspace descriptors and the
|
||
APM descriptors.
|
||
|
||
The GDT also contains 4 entries for APM segments. The APM segments
|
||
have byte granularity and their bases and limits are set at runtime.
|
||
The rest of the gdt_table (after the APM segments) is space for TSSes
|
||
and LDTs.
|
||
|
||
Jump to __KERNEL_CS:%eip to cause the GDT to be used. Now in
|
||
********** protected mode **********.
|
||
|
||
Reload all of the segment registers: Set the %ds, %es, %fs, and %gs
|
||
registers to __KERNEL_DS.
|
||
|
||
#ifdef CONFIG_SMP
|
||
|
||
Reload the stack pointer segment only (%ss) with __KERNEL_DS.
|
||
|
||
#else /* not CONFIG_SMP */
|
||
|
||
Reload the stack pointer (%ss:%esp) with stack_start.
|
||
|
||
#endif /* CONFIG_SMP */
|
||
|
||
Clear the LDT pointer to 0.
|
||
|
||
Clear the processor's Direction Flag (DF) to 0 for gcc.
|
||
|
||
|
||
4.12. Start other processors
|
||
|
||
|
||
For CONFIG_SMP builds, if this is not the first (Bootstrap) CPU, call
|
||
initialize_secondary(), which does not return. The secondary (AP)
|
||
processor(s) are initialized and then enter idle state until processes
|
||
are scheduled on them.
|
||
|
||
If this is the first or only CPU, call start_kernel(). (see below)
|
||
|
||
/* the calls above should never return, but in case they do: */
|
||
|
||
L6: jmp L6
|
||
|
||
|
||
|
||
5. Linux architecture-independent initialization
|
||
|
||
|
||
(from "linux/init/main.c")
|
||
|
||
"linux/init/main.c" begins execution with the start_kernel() function,
|
||
which is called from "linux/arch/i386/kernel/head.S". start_kernel()
|
||
never returns to its caller. It ends by calling the cpu_idle()
|
||
function.
|
||
|
||
|
||
5.1. start_kernel:
|
||
|
||
|
||
Interrupts are still disabled. Do necessary setups, then enable them.
|
||
|
||
Lock the kernel (BKL: big kernel lock).
|
||
|
||
Print the linux_banner string (this string resides in
|
||
"linux/init/version.c") using printk(). NOTE: printk() doesn't
|
||
actually print this to the console yet; it just buffers the string
|
||
until a console device registers itself with the kernel, then the
|
||
kernel passes the buffered console log contents to the registered
|
||
console device(s). There can be multiple registered console devices.
|
||
|
||
********** printk() can be called very early because it doesn't
|
||
actually print to anywhere. It just logs the message to "log_buf",
|
||
which is allocated statically in "linux/kernel/printk.c". The
|
||
messages that are saved in "log_buf" are passed to registered console
|
||
devices as they register. **********
|
||
|
||
|
||
5.1.1. More architecture-specific init
|
||
|
||
|
||
Call setup_arch(&command_line):
|
||
|
||
This performs architecture-specific initializations (details below).
|
||
Then back to architecture-independent initialization....
|
||
|
||
The remainder of start_kernel() is done as follows for all processor
|
||
architecures, although several of these function calls are to
|
||
architecture-specific setup/init functions.
|
||
|
||
|
||
5.1.2. Continue architecture-independent init
|
||
|
||
Print the kernel command line.
|
||
|
||
|
||
5.1.3. Parsing command line options
|
||
|
||
|
||
parse_options(command_line): Parse the kernel options on the command
|
||
line. This is a simple kernel command line parsing function. It
|
||
parses the command line and fills in the arguments and environment to
|
||
init (thread) as appropriate. Any command-line option is taken to be
|
||
an environment variable if it contains the character '='. It also
|
||
checks for options meant for the kernel by calling checksetup(), which
|
||
checks the command line for kernel parameters, these being specified
|
||
by declaring them using "__setup", as in:
|
||
|
||
|
||
|
||
______________________________________________________________________
|
||
__setup("debug", debug_kernel);
|
||
______________________________________________________________________
|
||
|
||
|
||
|
||
This declaration causes the debug_kernel() function to be called when
|
||
the string "debug" is scanned. See "linux/Documentation/kernel-
|
||
parameters.txt" for the list of kernel parameters.
|
||
|
||
These options are not given to init -- they are for internal kernel
|
||
use only. The default argument list for the init thread is {"init",
|
||
NULL}, with a maximum of 8 command-line arguments. The default
|
||
environment list for the init thread is {"HOME=/", "TERM=linux",
|
||
NULL}, with a maximum of 8 command-line environment variable settings.
|
||
In case LILO is going to boot us with default command line, it
|
||
prepends "auto" before the whole cmdline which makes the shell think
|
||
it should execute a script with such name. So we ignore all arguments
|
||
entered _before_ init=... [MJ]
|
||
|
||
|
||
5.1.4. trap_init
|
||
|
||
|
||
(in linux/arch/i386/kernel/traps.c)
|
||
|
||
Install exception handlers for basic processor exceptions, i.e., not
|
||
hardware device interrupt handlers.
|
||
|
||
Install the handler for the system call software interrupt.
|
||
|
||
Install handlers for lcall7 (for iBCS) and lcall27 (for Solaris/x86
|
||
binaries).
|
||
|
||
Call cpu_init() to do:
|
||
|
||
· initialize per-CPU state
|
||
|
||
· reload the GDT and IDT
|
||
|
||
· mask off the eflags NT (Nested Task) bit
|
||
|
||
· set up and load the per-CPU TSS and LDT
|
||
|
||
· clear 6 debug registers (0, 1, 2, 3, 6, and 7)
|
||
|
||
· stts(): set the 0x08 bit (TS: Task Switched) in CR0 to enable lazy
|
||
register saves on context switches
|
||
|
||
|
||
5.1.5. init_IRQ
|
||
|
||
|
||
(in linux/arch/i386/kernel/i8259.c)
|
||
|
||
Call init_ISA_irqs() to initialize the two 8259A interrupt controllers
|
||
and install default interrupt handlers for the ISA IRQs.
|
||
|
||
Set an interrupt gate for all unused interrupt vectors.
|
||
|
||
For CONFIG_SMP configurations, set up IRQ 0 early, since it's used
|
||
before the IO APIC is set up.
|
||
|
||
For CONFIG_SMP, install the interrupt handler for CPU-to-CPU IPIs that
|
||
are used for the "reschedule helper."
|
||
For CONFIG_SMP, install the interrupt handler for the IPI that is used
|
||
to invalidate TLBs.
|
||
|
||
For CONFIG_SMP, install the interrupt handler for the IPI that is used
|
||
for generic function calls.
|
||
|
||
For CONFIG_X86_LOCAL_APIC configurations, install the interrupt
|
||
handler for the self-generated local APIC timer IPI.
|
||
|
||
For CONFIG_X86_LOCAL_APIC configurations, install interrupt handlers
|
||
for spurious and error interrupts.
|
||
|
||
Set the system's clock chip to generate a timer tick interrupt every
|
||
HZ Hz.
|
||
|
||
If the system has an external FPU, set up IRQ 13 to handle floating
|
||
point exceptions.
|
||
|
||
|
||
5.1.6. sched_init
|
||
|
||
|
||
(in linux/kernel/sched.c)
|
||
|
||
|
||
· Set the init_task's processor ID.
|
||
|
||
· Clear the pidhash table. TBD: Why? isn't it in BSS?
|
||
|
||
· call init_timervecs()
|
||
|
||
· call init_bh() to init "bottom half" queues for timer_bh,
|
||
tqueue_bh, and immediate_bh.
|
||
|
||
|
||
5.1.7. time_init
|
||
|
||
|
||
(in linux/arch/i386/kernel/time.c)
|
||
|
||
Initialize the system's current time of day (xtime) from CMOS.
|
||
|
||
Install the irq0 timer tick interrupt handler.
|
||
|
||
|
||
5.1.8. softirq_init
|
||
|
||
|
||
(in linux/kernel/softirq.c)
|
||
|
||
|
||
5.1.9. console_init
|
||
|
||
|
||
(in linux/drivers/char/tty_io.c)
|
||
|
||
HACK ALERT! This is early. We're enabling the console before we've
|
||
done PCI setups etc., and console_init() must be aware of this. But
|
||
we do want output early, in case something goes wrong.
|
||
|
||
|
||
5.1.10. init_modules
|
||
|
||
|
||
(in linux/kernel/module.c)
|
||
|
||
For CONFIG_MODULES configurations, call init_modules(). This
|
||
initializes the size (or number of symbols) of the kernel symbol
|
||
table.
|
||
|
||
|
||
5.1.11. Profiling setup
|
||
|
||
|
||
if profiling ("profile=#" on the kernel command line): calculate the
|
||
kernel text (code) profile "segment" size; calculate the profile
|
||
buffer size in pages (round up); allocate the profile buffer:
|
||
prof_buffer = alloc_bootmem(size);
|
||
|
||
|
||
5.1.12. kmem_cache_init
|
||
|
||
|
||
(in linux/mm/slab.c)
|
||
|
||
|
||
5.1.13. sti
|
||
|
||
|
||
********** Interrupts are now enabled. **********
|
||
This allows "calibrate_delay()" (below) to work.
|
||
|
||
|
||
5.1.14. calibrate_delay
|
||
|
||
|
||
Calculate the "loops_per_jiffy" delay loop value and print it in
|
||
BogoMIPS.
|
||
|
||
|
||
5.1.15. INITRD setup
|
||
|
||
|
||
|
||
#ifdef CONFIG_BLK_DEV_INITRD
|
||
|
||
if (initrd_start && !initrd_below_start_ok &&
|
||
initrd_start < (min_low_pfn << PAGE_SHIFT)) {
|
||
printk("initrd overwritten (initrd_start < (min_low_pfn << PAGE_SHIFT)) - disabling it.\n");
|
||
initrd_start = 0; // mark initrd as disabled
|
||
}
|
||
|
||
#endif /* CONFIG_BLK_DEV_INITRD */
|
||
|
||
|
||
|
||
5.1.16. mem_init
|
||
|
||
|
||
(in linux/arch/i386/mm/init.c)
|
||
|
||
|
||
· Clear the empty_zero_page.
|
||
|
||
· Call free_all_bootmem() and add that released memory to
|
||
totalram_pages.
|
||
|
||
· Count the number of reserved RAM pages.
|
||
|
||
· Print the system memory sizes (free/total), kernel code size,
|
||
reserved memory size, kernel data size, kernel "init" size, and the
|
||
highmem size.
|
||
|
||
· For CONFIG_SMP, call zap_low_mappings().
|
||
|
||
********** get_free_pages() can be used after mem_init(). **********
|
||
|
||
|
||
5.1.17. kmem_cache_sizes_init
|
||
|
||
|
||
(in linux/mm/slab.c)
|
||
|
||
Set up remaining internal and general caches. Called after the
|
||
"get_free_page()" functions have been enabled and before smp_init().
|
||
|
||
********** kmalloc() can be used after kmem_cache_sizes_init().
|
||
**********
|
||
|
||
|
||
5.1.18. proc_root_init
|
||
|
||
|
||
(in linux/fs/proc/root.c)
|
||
|
||
For CONFIG_PROC_FS configurations:
|
||
|
||
· call proc_misc_init()
|
||
|
||
· mkdir /proc/net
|
||
|
||
· for CONFIG_SYSVIPC, mkdir /proc/sysvipc
|
||
|
||
· for CONFIG_SYSCTL, mkdir /proc/sys
|
||
|
||
· mkdir /proc/fs
|
||
|
||
· mkdir /proc/driver
|
||
|
||
· call proc_tty_init()
|
||
|
||
· mkdir /proc/bus
|
||
|
||
|
||
5.1.19. mempages = num_physpages;
|
||
|
||
|
||
|
||
5.1.20. fork_init(mempages)
|
||
|
||
|
||
(in linux/kernel/fork.c)
|
||
|
||
The default maximum number of threads is set to a safe value: the
|
||
thread structures can take up at most half of memory.
|
||
|
||
|
||
5.1.21. proc_caches_init()
|
||
|
||
|
||
(in linux/kernel/fork.c)
|
||
|
||
Call kmem_cache_create() to create slab caches for signal_act (signal
|
||
action), files_cache (files_struct), fs_cache (fs_struct),
|
||
vm_area_struct, and mm_struct.
|
||
5.1.22. vfs_caches_init(mempages)
|
||
|
||
|
||
(in linux/fs/dcache.c)
|
||
|
||
Call kmem_cache_create() to create slab caches for buffer_head,
|
||
names_cache, filp, and for CONFIG_QUOTA, dquot.
|
||
|
||
Call dcache_init() to create the dentry_cache and dentry_hashtable.
|
||
|
||
|
||
5.1.23. buffer_init(mempages)
|
||
|
||
|
||
(in linux/fs/buffer.c)
|
||
|
||
Allocate the buffer cache hash table and init the free list.
|
||
Use get_free_pages() for the hash table to decrease TLB misses; use
|
||
SLAB cache for buffer heads.
|
||
Setup the hash chains, free lists, and LRU lists.
|
||
|
||
|
||
5.1.24. page_cache_init(mempages)
|
||
|
||
|
||
(in linux/mm/filemap.c)
|
||
|
||
Allocate and clear the page-cache hash table.
|
||
|
||
|
||
5.1.25. kiobuf_setup()
|
||
|
||
|
||
(in linux/fs/iobuf.c)
|
||
|
||
Call kmem_cache_create() to create the kernel iobuf cache.
|
||
|
||
|
||
5.1.26. signals_init()
|
||
|
||
|
||
(in linux/kernel/signal.c)
|
||
|
||
Call kmem_cache_create() to create the "sigqueue" SLAB cache.
|
||
|
||
|
||
5.1.27. bdev_init()
|
||
|
||
|
||
(in linux/fs/block_dev.c)
|
||
|
||
Initialize the bdev_hashtable list heads.
|
||
|
||
Call kmem_cache_create() to create the "bdev_cache" SLAB cache.
|
||
|
||
|
||
5.1.28. inode_init(mempages)
|
||
|
||
|
||
(in linux/fs/inode.c)
|
||
|
||
|
||
· Allocate memory for the inode_hashtable.
|
||
|
||
· Intialize the inode_hashtable list heads.
|
||
|
||
· Call kmem_cache_create() to create the inode SLAB cache.
|
||
|
||
|
||
5.1.29. ipc_init()
|
||
|
||
|
||
(in linux/ipc/util.c)
|
||
|
||
For CONFIG_SYSVIPC configurations, call ipc_init().
|
||
|
||
The various System V IPC resources (semaphores, messages, and shared
|
||
memory) are initialized.
|
||
|
||
|
||
5.1.30. dquot_init_hash()
|
||
|
||
|
||
(in linux/fs/dquot.c)
|
||
|
||
For CONFIG_QUOTA configurations, call dquot_init_hash().
|
||
|
||
|
||
· Clear dquot_hash. TBD: Why? Is it in BSS? Yes.
|
||
|
||
· Clear dqstats. TBD: Why? Is it in BSS? Yes.
|
||
|
||
|
||
5.1.31. check_bugs()
|
||
|
||
|
||
(in linux/include/asm-i386/bugs.h)
|
||
|
||
|
||
· identify_cpu()
|
||
|
||
· For non-CONFIG_SMP configurations, print_cpu_info()
|
||
|
||
· check_config()
|
||
|
||
· check_fpu()
|
||
|
||
· check_hlt()
|
||
|
||
· check_popad()
|
||
|
||
· Update system_utsname.machine{byte 1} with boot_cpu_data.x86
|
||
|
||
|
||
5.1.32. Start other SMP processors (as applicable)
|
||
|
||
|
||
smp_init() works in one of three ways, depending upon the kernel
|
||
configuration.
|
||
|
||
For a uniprocessor (UP) system without an IO APIC (CONFIG_X86_IO_APIC
|
||
is not defined), smp_init() is empty -- it has nothing to do.
|
||
|
||
For a UP system with (an) IO APIC for interrupt routing, it calls
|
||
IO_APIC_init_uniprocessor().
|
||
|
||
For an SMP system, its main job is to call the architecture-specific
|
||
function "smp_boot_cpus()", which does the following.
|
||
|
||
|
||
· For CONFIG_MTRR kernels, calls mtrr_init_boot_cpu(), which must be
|
||
done before the other processors are booted.
|
||
· Stores and prints the BSP CPU information.
|
||
|
||
· Saves the BSP APIC ID and BSP logical CPU ID (latter is 0).
|
||
|
||
· If an MP BIOS interrupt routing table was not found, revert to
|
||
using only one CPU and exit.
|
||
|
||
· Verify existence of a local APIC for the BSP.
|
||
|
||
· If the "maxcpus" boot option was used to limit the number of CPUs
|
||
actually used to 1 (not SMP), then ignore the MP BIOS interrupt
|
||
routing table.
|
||
|
||
· Switch the system from PIC mode to symmetric I/O interrupt mode.
|
||
|
||
· Setup the BSP's local APIC.
|
||
|
||
· Use the CPU present map to boot the APs serially. Wait for each AP
|
||
to finish booting before starting the next one.
|
||
|
||
· If using (an) IO APIC {which is True unless the "noapic" boot
|
||
option was used}, setup the IO APIC(s).
|
||
|
||
|
||
5.1.33. Start init thread
|
||
|
||
|
||
We count on the initial thread going OK.
|
||
|
||
Like idlers, init is an unlocked kernel thread, which will make
|
||
syscalls (and thus be locked).
|
||
|
||
|
||
|
||
kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
|
||
|
||
|
||
|
||
{details below}
|
||
|
||
|
||
5.1.34. unlock_kernel()
|
||
|
||
|
||
Release the BKL.
|
||
|
||
|
||
5.1.35. current->need_resched = 1;
|
||
|
||
|
||
|
||
5.1.36. cpu_idle()
|
||
|
||
|
||
This function remains as process number 0. Its purpose is to use up
|
||
idle CPU cycles. If the kernel is configured for APM support or ACPI
|
||
support, cpu_idle() invokes the supported power-saving features of
|
||
these specifications. Otherwise it nominally executes a "hlt"
|
||
instruction.
|
||
|
||
{end of start_kernel()}
|
||
|
||
|
||
|
||
5.2. setup_arch
|
||
|
||
|
||
(in "linux/arch/i386/kernel/setup.c")
|
||
|
||
|
||
5.2.1. Copy and convert system parameter data
|
||
|
||
|
||
Copy and convert parameter data passed from 16-bit real mode to the
|
||
32-bit startup code.
|
||
|
||
|
||
5.2.2. For RAMdisk-enabled configs (CONFIG_BLK_DEV_RAM)
|
||
|
||
|
||
Initialize rd_image_start, rd_prompt, and rd_doload from the real-mode
|
||
parameter data.
|
||
|
||
|
||
5.2.3. setup_memory_region
|
||
|
||
|
||
Use the BIOS-supplied memory map to setup memory regions.
|
||
|
||
|
||
5.2.4. Set memory limits
|
||
|
||
|
||
Set values for the start of kernel code, end of kernel code, end of
|
||
kernel data, and "_end" (end of kernel code = the "brk" address).
|
||
|
||
Set values for code_resource start and end and data_resource start and
|
||
end.
|
||
|
||
|
||
5.2.5. parse_mem_cmdline
|
||
|
||
|
||
Parse any "mem=" parameters on the kernel command line and remember
|
||
them.
|
||
|
||
|
||
5.2.6. Setup Page Frames
|
||
|
||
|
||
Use the BIOS-supplied memory map to setup page frames.
|
||
|
||
Register available low RAM pages with the bootmem allocator.
|
||
|
||
Reserve physical page 0: "it's a special BIOS page on many boxes,
|
||
enabling clean reboots, SMP operation, laptop functions."
|
||
|
||
|
||
5.2.7. Handle SMP and IO APIC Configurations
|
||
|
||
|
||
For CONFIG_SMP, reserve the page immediately above page 0 for stack
|
||
and trampoline usage, then call smp_alloc_memory() to allocate low
|
||
memory for AP processor(s) real mode trampoline code.
|
||
|
||
For CONFIG_X86_IO_APIC configurations, call find_smp_config() to find
|
||
and reserve any boot-time SMP configuration information memory, such
|
||
as MP (Multi Processor) table data from the BIOS.
|
||
|
||
|
||
5.2.8. paging_init()
|
||
|
||
|
||
paging_init() sets up the page tables - note that the first 8 MB are
|
||
already mapped by head.S.
|
||
|
||
This routine also unmaps the page at virtual kernel address 0, so that
|
||
we can trap those pesky NULL-reference errors in the kernel.
|
||
|
||
|
||
5.2.9. Save the boot-time SMP configuration
|
||
|
||
|
||
For CONFIG_X86_IO_APIC configurations, call get_smp_config() to read
|
||
and save the MP table IO APIC interrupt routing configuration data.
|
||
|
||
For CONFIG_X86_LOCAL_APIC configurations, call init_apic_mappings().
|
||
|
||
|
||
5.2.10. Reserve INITRD memory
|
||
|
||
|
||
For CONFIG_BLK_DEV_INITRD configurations, if there is enough memory
|
||
for the initial RamDisk, call reserve_bootmem() to reserve RAM for the
|
||
initial RamDisk.
|
||
|
||
|
||
5.2.11. Scan for option ROMs
|
||
|
||
|
||
Call probe_roms() and reserve their memory space resource(s) if found
|
||
and valid. This is done for the standard video BIOS ROM image, any
|
||
option ROMs found, and for the system board extension ROM (space).
|
||
|
||
|
||
5.2.12. Reserve system resources
|
||
|
||
|
||
Call request_resource() to reserve video RAM memory.
|
||
|
||
Call request_resource() to reserve all standard PC I/O system board
|
||
resources.
|
||
|
||
{end of setup_arch()}
|
||
|
||
|
||
5.3. init thread
|
||
|
||
|
||
The init thread begins at the init() function in "linux/init/main.c".
|
||
This is always expected to be process number 1.
|
||
|
||
init() first locks the kernel and then calls do_basic_setup() to
|
||
perform lots of bus and/or device initialization {more detail below}.
|
||
After do_basic_setup(), most kernel initialization has been completed.
|
||
init() then frees any memory that was specified as being for
|
||
initialization only [marked with "__init", "__initdata",
|
||
"__init_call", or "__initsetup"] and unlocks the kernel (BKL).
|
||
|
||
init() next opens /dev/console and duplicates that file descriptor two
|
||
times to create stdin, stdout, and stderr files for init and all of
|
||
its children.
|
||
|
||
Finally init() tries to execute the command specified on the kernel
|
||
parameters command line if there was one, or an init program or script
|
||
if it can find one in {/sbin/init, /etc/init, /bin/init}, and lastly
|
||
/bin/sh. If init() cannot execute any of these, it panics ("No init
|
||
found. Try passing init= option to kernel.")
|
||
|
||
|
||
5.4. do_basic_setup {part of the init thread}
|
||
|
||
|
||
The machine is now initialized. None of the devices have been touched
|
||
yet, but the CPU subsystem is up and running, and memory and process
|
||
management works.
|
||
|
||
|
||
5.4.1. Be the reaper of orphaned children
|
||
|
||
|
||
The init process handles all orphaned tasks.
|
||
|
||
|
||
5.4.2. MTRRs
|
||
|
||
|
||
// SMP init is completed before this.
|
||
For CONFIG_MTRR, call mtrr_init() [in linux/arch/i386/kernel/mtrr.c].
|
||
|
||
|
||
5.4.3. SYSCTLs
|
||
|
||
|
||
For CONFIG_SYSCTL configurations, call sysctl_init() [in
|
||
linux/kernel/sysctl.c].
|
||
|
||
|
||
5.4.4. Init Many Devices
|
||
|
||
|
||
|
||
/*
|
||
* Ok, at this point all CPU's should be initialized, so
|
||
* we can start looking into devices..
|
||
*/
|
||
|
||
|
||
|
||
5.4.5. PCI
|
||
|
||
|
||
For CONFIG_PCI configurations, call pci_init() [in
|
||
linux/drivers/pci/pci.c].
|
||
|
||
|
||
5.4.6. Micro Channel
|
||
|
||
|
||
For CONFIG_MCA configurations, call mca_init() [in
|
||
linux/arch/i386/kernel/mca.c].
|
||
|
||
|
||
5.4.7. ISA PnP
|
||
|
||
|
||
For CONFIG_ISAPNP configurations, call isapnp_init() [in
|
||
linux/drivers/pnp/isapnp.c].
|
||
|
||
5.4.8. Networking Init
|
||
|
||
|
||
|
||
/* Networking initialization needs a process context */
|
||
sock_init();
|
||
|
||
|
||
|
||
[in linux/net/socket.c]
|
||
|
||
|
||
5.4.9. Initial RamDisk
|
||
|
||
|
||
|
||
#ifdef CONFIG_BLK_DEV_INITRD
|
||
|
||
real_root_dev = ROOT_DEV;
|
||
real_root_mountflags = root_mountflags;
|
||
if (initrd_start && mount_initrd)
|
||
root_mountflags &= ~MS_RDONLY; // change to read/write
|
||
else
|
||
mount_initrd =0;
|
||
|
||
#endif /* CONFIG_BLK_DEV_INITRD */
|
||
|
||
|
||
|
||
5.4.10. Start the kernel "context" thread (keventd)
|
||
|
||
|
||
[in linux/kernel/context.c]
|
||
|
||
|
||
5.4.11. Initcalls
|
||
|
||
|
||
Call all functions marked as "__initcall":
|
||
|
||
|
||
do_initcalls();
|
||
|
||
|
||
|
||
[in linux/init/main.c]
|
||
|
||
This initializes many functions and some subsystems --- in no specific
|
||
or guaranteed order unless fixed in their Makefiles --- if they were
|
||
built into the kernel, such as:
|
||
|
||
|
||
· APM: apm_init() {in linux/arch/i386/kernel/apm.c}
|
||
|
||
· cpuid: cpuid_init() {in linux/arch/i386/kernel/cpuid.c}
|
||
|
||
· DMI: dmi_scan_machine() {in linux/arch/i386/kernel/dmi_scan.c}
|
||
|
||
· microcode: microcode_init() {in linux/arch/i386/kernel/microcode.c}
|
||
|
||
· MSR: msr_init() {in linux/arch/i386/kernel/msr.c}
|
||
|
||
· partitions: partition_setup() {in linux/fs/partitions/check.s}
|
||
|
||
· file systems, pipes, buffer and cache management, various binary
|
||
format loaders, NLS character sets: too numerous to list {in
|
||
linux/fs/*}
|
||
|
||
· user cache (for limits): uid_cache_init() {in linux/kernel/user.c}
|
||
|
||
· kmem_cpu_cache: kmem_cpucache_init() {in linux/mm/slab.c}
|
||
|
||
· shmem: init_shmem_fs() {in linux/mm/shmem.c}
|
||
|
||
· kswapd: kswapd_init() {in linux/mm/vmscan.c}
|
||
|
||
· networking, TCP/IP, IPv6, sockets, 802.2, SNAP, LLC, X.25, AX.25,
|
||
IPX, kHTTPd, ATM LAN emulation (LANE), IP chains/forwarding,
|
||
NAT/masquerading, packet matching/filtering/logging, firewalling,
|
||
DECnet, bridging, and other networking protocols too numerous to
|
||
list {in linux/net/*}
|
||
|
||
· drivers, some of which are not exactly device drivers, but help out
|
||
with bus/device enumeration and initialization, such as:
|
||
|
||
· ACPI: acpi_init() {in linux/drivers/acpi/*}
|
||
|
||
· PCI: pci_proc_init() {in linux/drivers/pci/*}
|
||
|
||
· PCMCIA controllers {in linux/drivers/pcmcia/*}
|
||
|
||
· and...
|
||
|
||
· atm drivers {in linux/drivers/atm/*}
|
||
|
||
· block drivers {in linux/drivers/block/*}
|
||
|
||
· CD-ROM drivers {in linux/drivers/cdrom/*}
|
||
|
||
· character drivers {in linux/drivers/char/*}
|
||
|
||
· I2O drivers {in linux/drivers/i2o/*}
|
||
|
||
· IDE drivers {in linux/drivers/ide/*}
|
||
|
||
· input drivers (keyboard/mouse/joystick) {in linux/drivers/input/*}
|
||
|
||
· ISDN drivers {in linux/drivers/isdn/*}
|
||
|
||
· md, LVM, and RAID drivers {in linux/drivers/md/*}
|
||
|
||
· radio drivers {in linux/drivers/media/radio/*}
|
||
|
||
· video drivers {in linux/drivers/media/video/*}
|
||
|
||
· MTD drivers {in linux/drivers/mtd/*}
|
||
|
||
· network drivers, including PLIP, PPP, dummy, Ethernet, bonding,
|
||
Arcnet, hamradio, PCMCIA, Token Ring, and WAN
|
||
|
||
· SCSI logical and physical drivers {in linux/drivers/scsi/*}
|
||
|
||
· sound drivers {in linux/drivers/sound/*}
|
||
|
||
· telephony drivers {in linux/drivers/telephony/*}
|
||
|
||
· USB host controllers and device drivers {in linux/drivers/usb/*}
|
||
|
||
· video frame buffer drivers {in linux/drivers/video/*}
|
||
|
||
|
||
5.4.12. Filesystems
|
||
|
||
|
||
Call filesystem_setup():
|
||
|
||
· init_devfs_fs(); /* Header file may make this empty */
|
||
|
||
· For CONFIG_NFS_FS configurations, call init_nfs_fs().
|
||
|
||
· For CONFIG_DEVPTS_FS configurations, call init_devpts_fs().
|
||
|
||
[in linux/fs/filesystems.c]
|
||
|
||
|
||
5.4.13. IRDA
|
||
|
||
|
||
For CONFIG_IRDA configurations, call irda_device_init().
|
||
/* Must be done after protocol initialization */
|
||
[in linux/net/irda/irda_device.c]
|
||
|
||
|
||
5.4.14. PCMCIA
|
||
|
||
|
||
/* Do this last */
|
||
For CONFIG_PCMCIA configurations, call init_pcmcia_ds().
|
||
[in linux/drivers/pcmcia/ds.c]
|
||
|
||
|
||
5.4.15. Mount the root filesystem
|
||
|
||
|
||
|
||
mount_root();
|
||
|
||
|
||
|
||
[in linux/fs/super.c]
|
||
|
||
|
||
5.4.16. Mount the dev (device) filesystem
|
||
|
||
|
||
|
||
mount_devfs_fs ();
|
||
|
||
|
||
|
||
[in linux/fs/devfs/base.c]
|
||
|
||
|
||
5.4.17. Switch to the Initial RamDisk
|
||
|
||
|
||
|
||
#ifdef CONFIG_BLK_DEV_INITRD
|
||
|
||
if (mount_initrd && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {
|
||
// Start the linuxrc thread.
|
||
pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
|
||
if (pid > 0)
|
||
while (pid != wait(&i));
|
||
if (MAJOR(real_root_dev) != RAMDISK_MAJOR
|
||
|| MINOR(real_root_dev) != 0) {
|
||
error = change_root(real_root_dev,"/initrd");
|
||
if (error)
|
||
printk(KERN_ERR "Change root to /initrd: "
|
||
"error %d\n",error);
|
||
}
|
||
}
|
||
|
||
#endif /* CONFIG_BLK_DEV_INITRD */
|
||
|
||
|
||
|
||
See "linux/Documentation/initrd.txt" for more information on initial
|
||
RAM disks.
|
||
|
||
{end of do_basic_setup()}
|
||
|
||
|
||
|
||
6. Glossary
|
||
|
||
|
||
AP: Application Processor, any x86 processor other than the Bootstrap
|
||
Processor on IA-32 SMP systems
|
||
|
||
ACPI: Advanced Configuration and Power Interface
|
||
|
||
APIC: Advanced Programmable Interrupt Controller
|
||
|
||
APM: Advanced Power Management, a BIOS-managed power management
|
||
specification for personal computers
|
||
|
||
BSP: Bootstrap Processor, the primary booting processor on IA-32 SMP
|
||
systems
|
||
|
||
BSS: Block Started by Symbol: the uninitialized data segment
|
||
|
||
BKL: Big Kernel Lock, the Linux global kernel lock
|
||
|
||
CRn: Control Register n, i386-specific control registers
|
||
|
||
FPU: Floating Point Unit, a separate math coprocessor device
|
||
|
||
GB: gigabyte (1024 * 1024 * 1024 bytes)
|
||
|
||
GDT: Global Descriptor Table, an i386 memory management table
|
||
|
||
IA: Intel Architecture (also i386, x86)
|
||
|
||
IDT: Interrupt Descriptor Table, an i386-specific table that contains
|
||
information used in handling interrupts
|
||
|
||
initrd: initial RAM disk (see "linux/Documentation/initrd.txt")
|
||
|
||
IPC: Inter-Process Communication
|
||
|
||
IPI: Inter-processor Interrupt, a method of signaling interrupts
|
||
between multiple processors on an SMP system
|
||
|
||
IRDA: InfraRed Data Association
|
||
|
||
IRQ: Interrupt ReQuest
|
||
|
||
ISA: Industry Standard Architecture
|
||
|
||
KB: kilobyte (1024 bytes)
|
||
|
||
LDT: Local Descriptor Table, an i386-specific memory management table
|
||
that is used to describe memory for each non-kernel process
|
||
|
||
MB: megabyte (1024 * 1024 bytes)
|
||
|
||
MCA: Micro Channel Architecture, used in IBM PS/2 computers
|
||
|
||
MP: Multi-processor
|
||
|
||
MSW: Machine Status Word
|
||
|
||
MTRR: Memory Type Range Registers
|
||
|
||
PAE: Physical Address Extension: extends the address space to 64 GB
|
||
instead of 4 GB
|
||
|
||
PCI: Peripheral Component Interconnect, an industry standard for
|
||
connecting devices on a local bus in a computer system
|
||
PCMCIA: Personal Computer Memory Card International Association;
|
||
defines standards for PCMCIA cards and CardBus PC Cards
|
||
|
||
PIC: Programmable Interrupt Controller
|
||
|
||
PNP: Plug aNd Play
|
||
|
||
PSE: Page Size Extension: allows 4 MB pages
|
||
|
||
SMP: Symmetric Multi Processor/Processing
|
||
|
||
TLB: Translation Lookaside Buffer, i386-specific processor cache of
|
||
recent page directory and page table entries
|
||
|
||
TSS: Task State Segment, an i386-specific task data structure
|
||
|
||
UP: Uniprocessor (single CPU) system.
|
||
|
||
|
||
|
||
7. References
|
||
|
||
|
||
|
||
1. Tigran Aivazian, "Linux Kernel Internals" (URL:
|
||
http://www.moses.uklinux.net/patches/lki.html)
|
||
|
||
2. Werner Almesberger, x86 Booting. (URL:
|
||
ftp://icaftp.epfl.ch/pub/people/almesber/booting/)
|
||
|
||
3. Werner Almesberger, "LILO Generic boot loader for Linux: Technical
|
||
overview." December 4, 1998. Included in LILO distribution.
|
||
|
||
4. Werner Almesberger and Hans Lermen, Using the initial RAM disk
|
||
(initrd). (file: linux/Documentation/initrd.txt)
|
||
|
||
5. H. Peter Anvin, "The Linux/I386 Boot Protocol (file:
|
||
linux/Documentation/i386/boot.txt)
|
||
|
||
6. Michael Beck et al, "Linux Kernel Internals," second edition.
|
||
Addison-Wesley, 1998.
|
||
|
||
7. Ralf Brown's Interrupt List, URL: http://www.ctyme.com/intr/int.htm
|
||
{browsable}
|
||
|
||
8. Ralf Brown's Interrupt List, URL:
|
||
http://www.delorie.com/djgpp/doc/rbinter/ix/ {browsable}
|
||
|
||
9. Ralf Brown's Interrupt List, URL:
|
||
http://www.cs.cmu.edu/ ralf/files.html {zipped, not browsable}
|
||
|
||
10.
|
||
E820 memory sizing method: URL:
|
||
http://www.teleport.com/ acpi/acpihtml/topic245.htm
|
||
|
||
11.
|
||
IBM Personal Computer AT Technical Reference. 1985.
|
||
|
||
12.
|
||
IBM Personal System/2(r) and Personal Computer BIOS Interface
|
||
Technical Reference, second edition. 1988.
|
||
|
||
13.
|
||
Hans Lermen and Martin Mares, "Summary of empty_zero_page layout."
|
||
(file: linux/Documentation/i386/zero-page.txt)
|
||
|
||
14.
|
||
linux/Documentation directory files
|
||
|
||
15.
|
||
Martin Mares, "Video Mode Selection Support." (file:
|
||
linux/Documentation/svga.txt)
|
||
|
||
16.
|
||
Scott Maxwell, "Linux Core Kernel Commentary." Coriolis Press,
|
||
1999.
|
||
|
||
17.
|
||
Mindshare, Inc., Tom Shanley, "Pentium(r) Pro and Pentium(r) II
|
||
System Architecture," second edition. Addison-Wesley, 1998.
|
||
|
||
18.
|
||
Allesandro Rubini, "Linux Device Drivers." O'Reilly and
|
||
Associates, 1998.
|
||
|
||
|
||
19.
|
||
URL: ftp://linux01.gwdg.de/pub/cLIeNUX/interim/Janet_Reno.tgz
|
||
|
||
20.
|
||
URL: http://www.eecs.wsu.edu/~cs640/ (was dead at last check)
|
||
|
||
21.
|
||
URL: http://www.linuxbios.org + "Papers"
|
||
|
||
|
||
|
||
Table of Contents
|
||
|
||
|
||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||
1.1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||
1.2. This document . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||
1.3. Contributions . . . . . . . . . . . . . . . . . . . . . . . . 6
|
||
1.4. Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . 6
|
||
1.5. License . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
|
||
2. Linux init ("ASCII art") . . . . . . . . . . . . . . . . . . . 7
|
||
3. Linux early setup . . . . . . . . . . . . . . . . . . . . . . . 10
|
||
3.1. IA-32 Kernel Setup . . . . . . . . . . . . . . . . . . . . . 10
|
||
3.1.1. start_of_setup: . . . . . . . . . . . . . . . . . . . . . . 11
|
||
3.1.1.1. Read second hard drive DASD type . . . . . . . . . . . . 11
|
||
3.1.1.2. Check that LILO loaded us right . . . . . . . . . . . . . 11
|
||
3.1.1.3. Check old loader trying to load a big kernel . . . . . . 12
|
||
3.1.1.4. Determine system memory size . . . . . . . . . . . . . . 12
|
||
3.1.1.5. Video adapter modes . . . . . . . . . . . . . . . . . . . 12
|
||
3.1.1.6. Get Hard Disk parameters . . . . . . . . . . . . . . . . 13
|
||
3.1.1.7. Get Micro Channel bus information . . . . . . . . . . . . 13
|
||
3.1.1.8. Check for mouse . . . . . . . . . . . . . . . . . . . . . 13
|
||
3.1.1.9. Check for APM BIOS support . . . . . . . . . . . . . . . 13
|
||
3.1.1.10. Prepare to move to protected mode . . . . . . . . . . . 14
|
||
3.1.1.11. Enable address line A20 . . . . . . . . . . . . . . . . 14
|
||
3.1.1.12. Make sure any possible coprocessor is properly reset
|
||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
|
||
3.1.1.13. Mask all interrupts . . . . . . . . . . . . . . . . . . 15
|
||
3.1.1.14. Move to Protected Mode . . . . . . . . . . . . . . . . . 15
|
||
3.1.1.15. Jump to startup_32 code . . . . . . . . . . . . . . . . 15
|
||
3.2. Video Setup . . . . . . . . . . . . . . . . . . . . . . . . . 15
|
||
3.2.1. video: . . . . . . . . . . . . . . . . . . . . . . . . . . 16
|
||
3.2.1.1. basic_detect: . . . . . . . . . . . . . . . . . . . . . . 16
|
||
3.2.1.2. mode_params: . . . . . . . . . . . . . . . . . . . . . . 17
|
||
3.2.1.3. mopar_gr: . . . . . . . . . . . . . . . . . . . . . . . . 17
|
||
3.2.1.4. mode_menu: . . . . . . . . . . . . . . . . . . . . . . . 17
|
||
3.2.1.5. mode_set: . . . . . . . . . . . . . . . . . . . . . . . . 17
|
||
3.2.1.6. store_screen: . . . . . . . . . . . . . . . . . . . . . . 18
|
||
3.2.1.7. restore_screen: . . . . . . . . . . . . . . . . . . . . . 18
|
||
3.2.1.8. mode_table: . . . . . . . . . . . . . . . . . . . . . . . 19
|
||
3.2.1.9. mode_scan: . . . . . . . . . . . . . . . . . . . . . . . 19
|
||
3.2.1.10. svga_modes: . . . . . . . . . . . . . . . . . . . . . . 19
|
||
4. Linux architecture-specific initialization . . . . . . . . . . 21
|
||
4.1. startup_32: . . . . . . . . . . . . . . . . . . . . . . . . . 21
|
||
4.2. Set segment registers to known values . . . . . . . . . . . . 21
|
||
4.3. SMP BSP (Bootstrap Processor) check . . . . . . . . . . . . . 21
|
||
4.4. Initialize page tables . . . . . . . . . . . . . . . . . . . 21
|
||
4.5. Enable paging . . . . . . . . . . . . . . . . . . . . . . . . 21
|
||
4.6. Clear BSS . . . . . . . . . . . . . . . . . . . . . . . . . . 22
|
||
4.7. 32-bit setup . . . . . . . . . . . . . . . . . . . . . . . . 22
|
||
4.8. Copy boot parameters and command line out of the way . . . . 22
|
||
4.9. checkCPUtype . . . . . . . . . . . . . . . . . . . . . . . . 22
|
||
4.10. Count this processor . . . . . . . . . . . . . . . . . . . . 22
|
||
4.11. Load descriptor table pointer registers . . . . . . . . . . 22
|
||
4.12. Start other processors . . . . . . . . . . . . . . . . . . . 23
|
||
5. Linux architecture-independent initialization . . . . . . . . . 24
|
||
5.1. start_kernel: . . . . . . . . . . . . . . . . . . . . . . . . 24
|
||
5.1.1. More architecture-specific init . . . . . . . . . . . . . . 24
|
||
5.1.2. Continue architecture-independent init . . . . . . . . . . 24
|
||
5.1.3. Parsing command line options . . . . . . . . . . . . . . . 24
|
||
5.1.4. trap_init . . . . . . . . . . . . . . . . . . . . . . . . . 25
|
||
5.1.5. init_IRQ . . . . . . . . . . . . . . . . . . . . . . . . . 25
|
||
5.1.6. sched_init . . . . . . . . . . . . . . . . . . . . . . . . 26
|
||
5.1.7. time_init . . . . . . . . . . . . . . . . . . . . . . . . . 26
|
||
5.1.8. softirq_init . . . . . . . . . . . . . . . . . . . . . . . 26
|
||
5.1.9. console_init . . . . . . . . . . . . . . . . . . . . . . . 26
|
||
5.1.10. init_modules . . . . . . . . . . . . . . . . . . . . . . . 26
|
||
5.1.11. Profiling setup . . . . . . . . . . . . . . . . . . . . . 27
|
||
5.1.12. kmem_cache_init . . . . . . . . . . . . . . . . . . . . . 27
|
||
5.1.13. sti . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
|
||
5.1.14. calibrate_delay . . . . . . . . . . . . . . . . . . . . . 27
|
||
5.1.15. INITRD setup . . . . . . . . . . . . . . . . . . . . . . . 27
|
||
5.1.16. mem_init . . . . . . . . . . . . . . . . . . . . . . . . . 27
|
||
5.1.17. kmem_cache_sizes_init . . . . . . . . . . . . . . . . . . 28
|
||
5.1.18. proc_root_init . . . . . . . . . . . . . . . . . . . . . . 28
|
||
5.1.19. mempages = num_physpages; . . . . . . . . . . . . . . . . 28
|
||
5.1.20. fork_init(mempages) . . . . . . . . . . . . . . . . . . . 28
|
||
5.1.21. proc_caches_init() . . . . . . . . . . . . . . . . . . . . 28
|
||
5.1.22. vfs_caches_init(mempages) . . . . . . . . . . . . . . . . 29
|
||
5.1.23. buffer_init(mempages) . . . . . . . . . . . . . . . . . . 29
|
||
5.1.24. page_cache_init(mempages) . . . . . . . . . . . . . . . . 29
|
||
5.1.25. kiobuf_setup() . . . . . . . . . . . . . . . . . . . . . . 29
|
||
5.1.26. signals_init() . . . . . . . . . . . . . . . . . . . . . . 29
|
||
5.1.27. bdev_init() . . . . . . . . . . . . . . . . . . . . . . . 29
|
||
5.1.28. inode_init(mempages) . . . . . . . . . . . . . . . . . . . 29
|
||
5.1.29. ipc_init() . . . . . . . . . . . . . . . . . . . . . . . . 30
|
||
5.1.30. dquot_init_hash() . . . . . . . . . . . . . . . . . . . . 30
|
||
5.1.31. check_bugs() . . . . . . . . . . . . . . . . . . . . . . . 30
|
||
5.1.32. Start other SMP processors (as applicable) . . . . . . . . 30
|
||
5.1.33. Start init thread . . . . . . . . . . . . . . . . . . . . 31
|
||
5.1.34. unlock_kernel() . . . . . . . . . . . . . . . . . . . . . 31
|
||
5.1.35. current->need_resched = 1; . . . . . . . . . . . . . . . . 31
|
||
5.1.36. cpu_idle() . . . . . . . . . . . . . . . . . . . . . . . . 31
|
||
5.2. setup_arch . . . . . . . . . . . . . . . . . . . . . . . . . 32
|
||
5.2.1. Copy and convert system parameter data . . . . . . . . . . 32
|
||
5.2.2. For RAMdisk-enabled configs (CONFIG_BLK_DEV_RAM) . . . . . 32
|
||
5.2.3. setup_memory_region . . . . . . . . . . . . . . . . . . . . 32
|
||
5.2.4. Set memory limits . . . . . . . . . . . . . . . . . . . . . 32
|
||
5.2.5. parse_mem_cmdline . . . . . . . . . . . . . . . . . . . . . 32
|
||
5.2.6. Setup Page Frames . . . . . . . . . . . . . . . . . . . . . 32
|
||
5.2.7. Handle SMP and IO APIC Configurations . . . . . . . . . . . 32
|
||
5.2.8. paging_init() . . . . . . . . . . . . . . . . . . . . . . . 33
|
||
5.2.9. Save the boot-time SMP configuration . . . . . . . . . . . 33
|
||
5.2.10. Reserve INITRD memory . . . . . . . . . . . . . . . . . . 33
|
||
5.2.11. Scan for option ROMs . . . . . . . . . . . . . . . . . . . 33
|
||
5.2.12. Reserve system resources . . . . . . . . . . . . . . . . . 33
|
||
5.3. init thread . . . . . . . . . . . . . . . . . . . . . . . . . 33
|
||
5.4. do_basic_setup {part of the init thread} . . . . . . . . . . 34
|
||
5.4.1. Be the reaper of orphaned children . . . . . . . . . . . . 34
|
||
5.4.2. MTRRs . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
|
||
5.4.3. SYSCTLs . . . . . . . . . . . . . . . . . . . . . . . . . . 34
|
||
5.4.4. Init Many Devices . . . . . . . . . . . . . . . . . . . . . 34
|
||
5.4.5. PCI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
|
||
5.4.6. Micro Channel . . . . . . . . . . . . . . . . . . . . . . . 34
|
||
5.4.7. ISA PnP . . . . . . . . . . . . . . . . . . . . . . . . . . 34
|
||
5.4.8. Networking Init . . . . . . . . . . . . . . . . . . . . . . 35
|
||
5.4.9. Initial RamDisk . . . . . . . . . . . . . . . . . . . . . . 35
|
||
5.4.10. Start the kernel "context" thread (keventd) . . . . . . . 35
|
||
5.4.11. Initcalls . . . . . . . . . . . . . . . . . . . . . . . . 35
|
||
5.4.12. Filesystems . . . . . . . . . . . . . . . . . . . . . . . 37
|
||
5.4.13. IRDA . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
|
||
5.4.14. PCMCIA . . . . . . . . . . . . . . . . . . . . . . . . . . 37
|
||
5.4.15. Mount the root filesystem . . . . . . . . . . . . . . . . 37
|
||
5.4.16. Mount the dev (device) filesystem . . . . . . . . . . . . 37
|
||
5.4.17. Switch to the Initial RamDisk . . . . . . . . . . . . . . 37
|
||
6. Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
|
||
7. References . . . . . . . . . . . . . . . . . . . . . . . . . . 41
|
||
|
||
|
||
|