After the system starts power-on, the default program entry of the MIPs processor is 0xbfc00000. The address is in the address area of kseg1 without caching, and the corresponding physical address is 0x1fc00000, that is, the CPU starts to get the first command from 0x1fc00000. This address has been determined as the flash location on the hardware. bootloader copies the Linux kernel image to a idle address in Ram, there is usually a memory movement operation. The destination address is specified in arch/MIPS/makefile:
Core-$ (config_mips_adm5120) + = ARCH/MIPS/adm5120/
Load-$ (config_mips_adm5120) + = 0xffffffff80002000
In the end, the bootloader will move the kernel to the physical address 0x002000.
The load address specified in makefile above will be written to arch/MIPS/kernel/vmlinux. LDS by the compilation system:
Output_arch (MIPs)
Entry (kernel_entry)
Jiffies = jiffies_64;
Sections
{
. = 0xffffffff80002000;
/* Read-only */
_ Text =.;/* Text and read-only data */
. Text :{
* (. Text)
...
This file will eventually be passed to GCC in the form of the parameter-xlinker -- script-xlinker vmlinux. LDS, and finally to the linker LD to control its behavior. LD links the address of the. text section to 0xffffffff80002000.
The entry point of the kernel ELF file, that is, the address that the bootloader directly jumps to after moving the kernel, which is written by the LD into the elf header, it tries to set the entry point in sequence using the following method, and stops when the entry is successful:
A. command line option-e entry
B. Entry (Symbol) in the script)
C. If the start symbol is defined, use the start symbol (Symbol)
D. If the. text section exists, use the address of the first byte.
E. Address 0
Note that in the above LD script, the entry point of the kernel is set to kernel_entry using the entry macro. Therefore, the First Command executed after the kernel obtains control is at kernel_entry.
The first phase of Linux kernel startup starts from the/ARCH/MIPS/kernel/head. s file. The kernel entry function kernel_entry () is defined in the/ARCH/MIPS/kernel/head. s file. The kernel_entry () function is an architecture-related assembly language. It first initializes the kernel stack segment to prepare the first process in the creation system, next, use a loop to clear the uninitialized data segment (BSS segment, between _ edata and _ end) of the kernel image, and finally jump to/init/main. start_kernel () in C initializes the Code related to the hardware platform.
**************************************** *****
Nested (kernel_entry, 16, SP) # kernel entry point
Declare the kernel_entry function. The stack of the function is 16 bytes. The return address is saved in the $ SP register.
-----------------------------
Declaration function entry
# Define nested (symbol, framesize, RPC )/
. Globl symbol ;/
. Align 2 ;/
. Type symbol, @ function ;/
. Ent symbol, 0 ;/
Symbol:. Frame sp, framesize, RPC
The Assembly pseudo-instruction frame is used to declare the STACK layout.
It has three parameters:
1) The first parameter framereg: Declares the register used to access the local stack, which is generally $ sp.
2) The second parameter framesize indicates the size of the allocated stack of the function.
$ SP + framesize = original $ sp.
3) The third parameter, returnreg, is used to save the return address.
----------------------------
Kernel_entry_setup # CPU specific setup
----------------------------
This macro is empty, defined in the include/ASM-MIPS/Mach-generic/kernel-entry-init.h file.
Some MIPS CPUs require additional control registers, which are related to specific platforms. Generally, they are empty macros. Some multi-core MIPS point all the core entries at startup to the kernel_entry, then, forking in the macro, boot core continues, and the rest continues to judge the loop until the boot core wakes up.
----------------------------
Setup_c0_status_pri
Set cp0_status register
----------------------------
. Macro setup_c0_status_pri
# Ifdef config_64bit
Setup_c0_status st0_kx 0
# Else
Setup_c0_status 0 0
# Endif
. Endm
----------------------------
Arc64_twiddle_pc
The operation is null unless config_arc64 is used.
-----------------------------
# Ifdef config_mips_mt_smtc
Mtc0 zero, cp0_tccontext _ bss_start
Mfc0 T0, cp0_status
Ori T0, T0, 0xff1f
Xori T0, T0, 0x001e
Mtc0 T0, cp0_status
# Endif/* config_mips_mt_smtc */
Macro-defined config_mips_mt_smtc is defined when multi-core smtc Linux is used. Generally, this parameter is not considered.
MIPs has developed the ultimate version of SMP Linux, called smtc (thread context Symmetric Multi-processing) Linux.
Smtc Linux can understand the concept of lightweight TC and reduce some overhead related to SMP Linux.
----------------------------
Ptr_la T0, _ bss_start # Clear. BSS
Long_s zero, (t0)
Ptr_la T1, _ bss_stop-longsize
1:
Ptr_addiu T0, longsize
Long_s zero, (t0)
BNE T0, T1, 1B
Clear the BSS segment and clear 0.
Variables _ bss_start and _ bss_stop are defined in the connection file ARCH/MIPS/kernel/vmlinux. LDS.
--------------------------------
Long_s A0, fw_arg0 # firmware arguments
Long_s A1, fw_arg1
Long_s A2, fw_arg2
Long_s A3, fw_arg3
The boot parameters passed by bootloader to the kernel are saved in the fw_arg0, fw_arg1, fw_arg2, and fw_arg3 variables.
The variable fw_arg0 is the number of kernel parameters, and the rest are string pointers in *** = XXXX format.
----------------------------------
Mtc0 zero, cp0_context # clear context register
Clear context register of cp0, which is used to save the starting address of the page table.
----------------------------------
Ptr_la $28, init_thread_union
Initialize the $ GP register. The Register address points to a union,
Thread_size. The minimum value is a thread_info structure.
---------------------------------
Ptr_li sp, _ thread_size-32
Ptr_addu sp, $28
Set the $ SP register and stack pointer. $ Sp = (init_thread_union address) + _ thread_size-32
$ SP points to the end address of the union structure-32 byte address.
-----------------------------------
Set_saved_sp sp, T0, T1
Save the stack address $ SP of the CPU core to the array of kernelsp [nr_cpus.
---------------------------------
If the config_smp macro is defined, that is, multiple CPU cores.
. Macro set_saved_sp stackp temp temp2
# Ifdef config_mips_mt_smtc
Mfc0/temp, cp0_tcbind
# Else
Mfc0/temp, cp0_context
# Endif
Long_srl/temp, ptebase_shift
Long_s/stackp, kernelsp (/temp)
. Endm
If the config_smp macro is not defined, a single CPU core is used.
. Macro set_saved_sp stackp temp temp2
Long_s/stackp, kernelsp
. Endm
The definition of the variable kernelsp is in the arch/MIPS/kernel/setup. c file.
Unsigned long kernelsp [nr_cpus];
Save the stack address $ SP of the CPU core to the array of kernelsp [nr_cpus.
---------------------------------
Ptr_subu sp, 4 * szreg # init Stack pointer
---------------------------------
J start_kernel
End (kernel_entry)
Finally, jump to start_kernel () in/init/Main. C to initialize the Code related to the hardware platform.
----------------------------------
**************************************** ******
The init_thread_union variable is defined in the arch/MIPS/kernel/init_task.c file.
Union thread_union init_thread_union
_ Attribute _ (_ Section _ (". Data. init_task "),
_ Aligned _ (thread_size) =
{Init_thread_info (init_task )};
The first phase of Linux kernel startup starts from the/ARCH/MIPS/kernel/head. s file.
The kernel entry function kernel_entry () is defined in the/ARCH/MIPS/kernel/head. s file.
The kernel_entry () function is an architecture-related assembly language. It first initializes the kernel stack segment to prepare the first process in the creation system, then, use a loop to clear the uninitialized data segment (BSS segment, between _ edata and _ end) of the kernel image,
Finally, jump to start_kernel () in/ARCH/MIPS/kernel/Main. C to initialize the Code related to the hardware platform.
The start_kernel () function is described below.
**************************************** ***
Asmlinkage void _ init start_kernel (void)
{
---------------------------------
Char * command_line;
Extern struct kernel_param _ start ___ Param [], _ Stop ___ Param [];
Defines the parameter data structure of the core.
---------------------------------
Smp_setup_processor_id ();
Set the ID number of the CPU core of an SMP multi-core. The single core does not perform any operations, and we do not care about it.
---------------------------------
Unwind_init ();
In the mips architecture, this function is an empty function (setup_arch may be called to configure the related functions of the core)
---------------------------------
Lockdep_init ();
Initialize the hash table of the core dependency.
---------------------------------
Local_irq_disable ();
Disable the interruption of the current CPU Core
---------------------------------
Early_boot_irqs_off ();
The static global variable early_boot_irqs_enabled is used to help us debug the code,
This tag helps us to know whether it is in the "Early bootup code ",
You can also use this flag to warn whether an invalid interrupt is opened.
And early_boot_irqs_on () function configuration, refer to the following.
---------------------------------
Early_init_irq_lock_class ();
Each interrupt is described by an IRQ Descriptor (struct irq_desc.
The main function of this function is to set the locks of all IRQ Descriptors (struct irq_desc) to uniform locks,
Or every IRQ Descriptor (struct irq_desc) has a small lock.
---------------------------------
Lock_kernel ();
Obtain a large kernel lock, which locks the entire kernel.
---------------------------------
Tick_init ();
If the macro config_generic_clockevents definition is not defined, this function is an empty function,
If this macro is defined, initialize the tick control function and register the clockevents framework.
---------------------------------
Boot_cpu_init ();
For a CPU core system, set the first CPU core to an active CPU core.
For a single CPU core system, set the CPU core to an active CPU core.
See Linux-MIPS startup analysis (2-1).
---------------------------------
Page_address_init ();
When the config_highmem macro is defined and the want_page_virtual macro is not defined, a non-empty function is used.
In other cases, empty functions are used.
---------------------------------
Printk (kern_notice );
Printk (linux_banner );
Output the printed version information.
---------------------------------
Setup_arch (& command_line );
Each architecture has its own setup_arch () function, which is related to the architecture.
How do I determine the setup_arch () function of the compiled architecture?
It is mainly determined by the arch variable in the makefile at the top layer of the Linux source code tree.
For example, the mips architecture.
Subarch: = MIPS
Arch? = $ (Subarch)
---------------------------------
Setup_command_line (command_line );
Save the unchanged comand_line to the character array static_command_line.
Save boot_command_line to the character array saved_command_line.
---------------------------------
Unwind_setup ();
Empty function.
---------------------------------
Setup_per_cpu_areas ();
If the config_smp macro is not defined, this function is empty.
If the config_smp macro is defined,
The setup_per_cpu_areas () function allocates memory for each CPU and copies data in. Data. percpu segments.
---------------------------------
If the config_smp macro is not defined, this function is empty.
If the config_smp macro is defined, this function
Smp_prepare_boot_cpu ();
---------------------------------
Sched_init ();
Core Process scheduler initialization takes precedence over any interruptions (including timer interruptions ).
And the initialization process 0 is the idle process, but the need_resched flag of the idle process is not set,
To complete the remaining startup part of the kernel.
---------------------------------
Preempt_disable ();
Kernel preemption. Increase the value of the preempt_count Member of the struct thread_info structure of the current process by 1.
---------------------------------
Create zonelist in the management area of each node to facilitate the use of fallback for memory allocation.
The function of this linked list: This linked list is set in the next management area when an allocation cannot be met.
At the end of the test, the allocation will be rolled back from zone_highmem to zone_normal,
When zone_normal is returned to zone_dma During allocation, it will not be rolled back.
Build_all_zonelists ();
---------------------------------
Page_alloc_init ();
---------------------------------
In the mips architecture, this function has been called once in the arch_mem_init () function.
For detailed analysis of this function, see Linux-MIPS startup analysis (4).
So this function returns directly.
Parse_early_param ();
---------------------------------
Print the Linux Startup command line parameters.
Printk (kern_notice "kernel command line: % s/n", boot_command_line );
---------------------------------
This function re-analyzes and processes the Linux Startup command line parameters.
The two variables _ start ___ PARAM and _ Stop ___ Param are
The link script is defined in arch/MIPS/kernel/vmlinux. LDS.
The last parameter is the function called when the Linux Startup command line parameter cannot be identified.
Parse_args ("booting kernel", static_command_line, _ start ___ Param,
_ Stop ___ param-_ start ___ Param, & unknown_bootoption );
---------------------------------
Check whether the interrupt is enabled. If yes, disable it.
If (! Irqs_disabled ()){
Local_irq_disable ();
}
---------------------------------
Sort_main_extable ();
This function calls the function table (exception table) for Kernel-created exception handling)
Heap sorting based on Abnormal Vector Numbers.
---------------------------------
Set the exception handling function of the CPU, refill TLB, cache error, and initialization of the common exception handling table.
Trap_init ();
---------------------------------
Initialize the RCU mechanism. This step must be earlier than the local timer initialization.
Rcu_init ();
---------------------------------
Used to initialize the irq_desc [] array of registers and interrupt descriptors related to the interrupt processing hardware,
Each interrupt number has a corresponding Interrupt Descriptor.
See Linux-MIPS startup analysis (11).
Init_irq ();
--------------------------------
During the initialization phase, the system dynamically allocates four hashtable addresses and stores their addresses in the pid_hash [] array.
It is easy to find the process descriptor address from the PID.