Linux 2.6 startup Process analysis __linux

Source: Internet
Author: User

The kernel can pass a string command line at boot time to control the process by which the kernel starts, for example:

"Console=ttys2,115200 mem=64m@0xa0000000"

Here specifies the console is a serial port 2, baud rate is 115200, memory size is 64M, physical base site is 0xa0000000.

In addition, we can define some global variables in the kernel, using these global variables to control the configuration of the kernel, for example, the USB driver defines

static int nousb; /* Disable USB built into kernel image * *

This variable is 1, the entire USB driver is not initialized, and if you want to set it to 1, you can add nousb=1 to the string command line.

Before you manipulate the variable, let the system know the variable by:

__module_param_call ("", nousb,param_set_bool,param_get_bool,&nousb,0444);

__module_param_call This macro is defined in kernel/include/linux/moduleparam.h

The prototype is as follows:

#define __module_param_call (prefix, name, set, GET, ARG, perm)

static char __param_str_# #name [] = prefix #name; /

static struct Kernel_param const __param_# #name/

__ATTRIBUTE_USED__/

__ATTRIBUTE__ ((unused,__section__ ("__param"), aligned (sizeof (void *)))

= {__param_str_# #name, perm, set, GET, arg}

It defines a kernel_param type of variable that is placed in a segment __param,

The KERNEL_PARAM structure is defined as:

struct Kernel_param {

const char *name;

unsigned int perm;

PARAM_SET_FN set;

PARAM_GET_FN get;

void *arg;

};

__param This paragraph of the statement that some of the platform is in arch/. /.. /VMLINUX.LDS.S, and most platforms are put into

Kernel/include/asm-generic/vmlinux.lds.h, the definition is as follows:

__param:at (ADDR (__param)-Load_offset) {/

Vmlinux_symbol (__start___param) =.; /

* (__param)/

Vmlinux_symbol (__stop___param) =.; /

}

When the kernel starts, the string command is parsed, and in kernel/init/main.c, the kernel boot function start_kernel

The outer array is declared:

extern struct Kernel_param __start___param[], __stop___param[];

The function is then called to parse the Parse_args array:

Parse_args ("Booting kernel", command_line, __start___param,

__stop___param-__start___param,

&unknown_bootoption);

Where Command_line is the string command line to parse, unknown_bootoption is a function pointer that gets the value of the = to the right of the specified parameter.

Parse_args will find the same Kernel_param variable in the array as the NOUSB name and call its set function to pay the value.

Determination of kernel startup address

The kernel compile link process relies on vmlinux.lds files, taking arm as an example Vmlinux.lds file is located in Kernel/arch/arm/vmlinux.lds,

However, this file is generated by vmlinux-armv.lds.in, depending on the compilation options of different source files can also be vmlinux-armo.lds.in,

Vmlinux-armv-xip.lds.in.

The Vmlinux-armv.lds generation process is in Kernel/arch/arm/makefile

Ldscript = arch/arm/vmlinux-armv.lds.in

Arch/arm/vmlinux.lds:arch/arm/makefile $ (ldscript)/

$ (wildcard include/config/cpu/32.h)/

$ (wildcard include/config/cpu/26.h)/

$ (wildcard include/config/arch/*.h)

@echo ' Generating $@ '

@sed ' s/textaddr/$ (textaddr)/;s/dataaddr/$ (dataaddr)/' $ (ldscript) >$@

Contents of vmlinux-armv.lds.in File:

Output_arch (ARM)

ENTRY (stext)

SECTIONS

{

. = TEXTADDR;

. init: {/* init code and Data */

_stext =.;

__init_begin =.;

* (. Text.init)

__proc_info_begin =.;

* (. Proc.info)

__proc_info_end =.;

__arch_info_begin =.;

* (. Arch.info)

__arch_info_end =.;

__tagtable_begin =.;

* (. taglist)

__tagtable_end =.;

* (. Data.init)

. = ALIGN (16);

__setup_start =.;

* (. Setup.init)

__setup_end =.;

__initcall_start =.;

* (. Initcall.init)

__initcall_end =.;

. = ALIGN (4096);

__init_end =.;

}

Where TEXTADDR is the kernel-initiated virtual address, defined in Kernel/arch/arm/makefile:

Ifeq ($ (config_cpu_32), y)

PROCESSOR = ARMV

TEXTADDR = 0xc0008000

Ldscript = arch/arm/vmlinux-armv.lds.in

endif

Note that this is a virtual address and not a physical address.

In general, after generating vmlinux, then compress the kernel into zimage, the compressed directory is kernel/arch/arm/boot.

Download to Flash is the compressed zimage file, Zimage is composed of compressed vmlinux and decompression program, as shown in the following figure:

|-----------------|/     |-----------------|

| |                  /    | |

|   | /   | Decompress code |

|    Vmlinux |     / |-----------------| Zimage

|     |                  /| |

|      |                  | |

|      |                  | |

|      |                  | |

|     | /|-----------------|

|    | /

|   | /

| | /

|-----------------|/

The Zimage link script is also called Vmlinux.lds, located in kernel/arch/arm/boot/compressed.

is generated by the vmlinux.lds.in file in the same directory, which reads as follows:

Output_arch (ARM)

ENTRY (_start)

SECTIONS

{

. = LOAD_ADDR;

_load_addr =.;

. = Text_start;

_text =.;

. Text: {

_start =.;

Where load_addr is the RAM offset address of the uncompressed code in the Zimage, Text_start is the offset address of the kernel RAM boot, and this address is the physical address.

In the Kernel/arch/arm/boot/makefile file, you define:

Ztextaddr =0

ZRELADDR = 0xa0008000

ZTEXTADDR is the RAM offset address of the uncompressed code, ZRELADDR is the offset address of the kernel Ram boot, where the specified ZTEXTADDR address is shown as 0,

Obviously not, because the RAM starting address on my platform is 0xa0000000, and in the makefile file I see a few lines of comments set to that address:

# We now have a PIC decompressor implementation. Decompressors Running

# from RAM should not define ZTEXTADDR. Decompressors running directly

# from ROM or Flash must define ZTEXTADDR (preferably via the config)

His consciousness is that if you are decompressing in RAM, you do not have to specify its running address in RAM, and you must specify his address if it is in Flash. So

Here the ZTEXTADDR is specified as 0, which means that no address is actually specified.

There is one line of script in the Kernel/arch/arm/boot/compressed/makefile file:

Sedflags = s/text_start/$ (ztextaddr)/;s/load_addr/$ (zreladdr)/;s/bss_start/$ (ZBSSADDR)/

Make Text_start = Ztextaddr,load_addr = zreladdr.

The build process for this vmlinux.lds is as follows:

Vmlinux.lds:vmlinux.lds.in Makefile $ (topdir)/arch/$ (Arch)/boot/makefile $ (topdir)/.config

@sed "$ (sedflags)" < vmlinux.lds.in > $@

The above is my analysis of the kernel boot address, summed up the kernel boot address settings:

1, set the Kernel/arch/arm/makefile file in the

TEXTADDR = 0xc0008000

Kernel-initiated virtual address

2, set the Kernel/arch/arm/boot/makefile file in the

ZRELADDR = 0xa0008000

Kernel-Initiated Physical address

If you need to start from flash, you need to set up

ZTEXTADDR address.

Kernel decompression Process

Kernel compression and decompression code are all in the directory kernel/arch/arm/boot/compressed,

When the compilation is complete, it will produce the files Vmlinux, HEAD.O, MISC.O, HEAD-XSCALE.O, PIGGY.O,

HEAD.O is the kernel of the head file, responsible for the initial settings;

MISC.O will be mainly responsible for the decompression of the kernel, after HEAD.O;

The HEAD-XSCALE.O file is primarily for XScale initialization and will be merged with HEAD.O at link time;

PIGGY.O is an intermediate file, is actually a compressed kernel (kernel/vmlinux), but did not initialize the file and extract the file link just;

Vmlinux is (no--lw:zimage is a compressed kernel) compressed core, is composed of piggy.o, HEAD.O, MISC.O, HEAD-XSCALE.O.

After bootloader completes the system boot and after the Linux kernel is transferred into memory, call Bootlinux (),

This function jumps to the starting position of the kernel. If the kernel is not compressed, it can be started.

If the kernel compressed, then decompression, in the compressed kernel head has decompression procedures.

Compressed kernel entrance first file source location in Arch/arm/boot/compressed/head. S

It will call the function Decompress_kernel (), which in the file arch/arm/boot/compressed/misc.c,

Decompress_kernel () also calls Proc_decomp_setup (), Arch_decomp_setup () to set,

Then invoke Gunzip () after printing out the information "uncompressing Linux ...". Place the kernel at the specified location.

The following analysis head. S file:

(1) For all kinds of ARM CPU debug output settings, through the definition of macros to unify the operation.

(2) Set kernel start and end address, save architecture ID.

(3) If in ARM2 above CPU, uses the ordinary user mode, then rises to the Super user mode, then shuts off the interruption.

(4) Analysis of LC0 structure Delta offset, determine whether the need to overload the kernel address (R0 deposit offset, determine whether the R0 is 0).

Here is the need to overload the kernel address, I thought the main analysis Arch/arm/boot/makefile, arch/arm/boot/compressed/makefile

And arch/arm/boot/compressed/vmlinux.lds.in three files, mainly looking at the location of the main segment of the vmlinux.lds.in link file,

LOAD_ADDR (_LOAD_ADDR) =0xa0008000, and the location of Text_start (_text, _start) is only set to 0,bss_start (__bss_start) =align (4).

The result depends on how the kernel is decompressed, that is, whether the kernel is in memory (RAM) or flash before extracting it,

Because of this, our bootloader moves the compressed kernel (zimage) to the 0xa0008000 position of RAM, and our compressed kernel is in the Order of memory (RAM) from the 0xa0008000 address,

So the offset that our r0 gets is the load address (0xa0008000). The next task is to convert the relative address of the kernel mirror to the physical address of the memory, that is, to overload the kernel address.

(5) The kernel address needs to be overloaded to add r0 offsets to the BSS region and got table.

(6) Empty the BSS stack space R2-R3.

(7) To establish a C program to run the required cache, and assigned to 64K stack space.

(8) At this time R2 is the end of the cache address, R4 is the kernel of the final address, R5 is the kernel file of the beginning of the address. Check to see if the address is conflicting.

The R5 equals R2 so that the decompress kernel address is after the 64K stack.

(9) the function Decompress_kernel () that calls the file misc.c, extracts the kernel at the end of the cache (R2 address). At this point the Register values change as follows:

R0 is the size of the kernel after decompression

R4 is the address when kernel is executed

R5 is the starting address for kernel after decompression

R6 is CPU Type value (processor ID)

R7 is the system type value (architecture ID)

(10) After the kernel of the Reloc_start code copy (after R5+r0), first clear the cache, and then execute the Reloc_start.

(one) Reloc_start overloads the R5 start kernel at the R4 address.

(12) Clear the cache content, close the cache, the R7 architecture ID in the R1, execute R4 start kernel code.

The following is a brief introduction to the decompression process, which is the function Decompress_kernel implementation:

The decompression code is located in the kernel/lib/inflate.c,inflate.c from the gzip source program. Contains a number of direct references to global data.

You need to embed it directly into your code when you use it. gzip compressed files always look for duplicate strings in the range of the first 32K bytes to encode,

A decompression buffer of at least 32K bytes is required for decompression, which is defined as window[wsize]. INFLATE.C uses Get_byte () to read the input file,

It is defined as a macro to improve efficiency. The input buffer pointer must be defined as a decrement operation in the inptr,inflate.c. INFLATE.C Call Flush_window ()

To output the extracted byte string in the window buffer, each output length is represented by a outcnt variable. In Flush_window (), it is also necessary

CRC must be computed on the output byte string and the CRC variable should be refreshed. Call MAKECRC () initialize the CRC calculation table before calling Gunzip () to begin decompression.

Finally Gunzip () returns 0 to indicate that the decompression was successful.

We will see this output at the beginning of the kernel startup:

Uncompressing linux...done, booting the kernel.

This is also output by the Decompress_kernel function, which calls the puts () output string,

The puts is implemented in Kernel/include/asm-arm/arch-pxa/uncompress.h.

Perform the decompression process and return to head. In S, start the kernel:

CALL_KERNEL:BL Cache_clean_flush

BL Cache_off

mov r0, #0

mov r1, R7 @ Restore Architecture number

mov pc, r4 @ call kernel

The real kernel is starting below.

Assembly section (1)

In the online reference to a lot of masters of the article, and added a little of their content, sorted out, there are many do not understand the place, but also there will be the wrong place to understand, hope the master pointing, they will continue to modify

When you enter the Linux kernel, ARCH/ARM/KERNEL/HEAD-ARMV. S is the first file that the kernel executes, including from the kernel Portal entry (stext) to

Start_kernel the initialization code between the two, the following is an example of the platform Intel pxa270 I use to illustrate his assembly code:

1. Section ". Text.init", #alloc, #execinstr

2. Type stext, #function

/* Kernel entry point * *

3 ENTRY (stext)

4 mov R12, r0

/* Program status, prohibit Fiq, IRQ, Set svc mode * *

5 mov r0, #F_BIT | I_bit | Mode_svc @ Make sure SVC mode

6 msr Cpsr_c, R0 @ and all IRQs disabled

/* Determine the CPU type, look for the CPU ID value that is running and the ID value supported by the Linux compilation support.

7 BL __lookup_processor_type

/* Judge if the value of R10 is 0, then the function execution error, jump to error handling, * *

/* ERROR handling function __ERROR implementation code defined in DEBUG-ARMV. s, here is no longer too much to introduce the * *

8 Teq R10, #0 @ Invalid processor?

9 Moveq r0, # ' P ' @ Yes, error ' P '

Ten beq __error

/* Judge the system type to see if the architecture type value of the R1 register supports/*

One BL __lookup_architecture_type

/* Judge if the value of R7 is 0, then the function execution error, jump to error handling, * *

Teq R7, #0 @ invalid architecture?

Moveq r0, # ' a ' @ Yes, error ' a '

BEQ __error

/* Create a core page table * *

BL __create_page_tables

ADR LR, __ret @ return address

Add pc, R10, #12 @ initialise processor

@ (return control reg)

Line 5th, ready to enter the SVC mode while shutting down interrupts (i_bit) and fast Interrupts (F_bit)

Line 7th, look at the processor type, primarily to get the processor ID and flags for the page table.

Line 11th, look at some architectural information.

Line 15th, create the page table.

Line 17th, jump to the processor's initialization function, whose function address is obtained from the __lookup_processor_type,

Note that the 16th line, when the processor initialization is complete, will jump directly to __ret to execute,

This is because the final statement of the initialization function is MOV pc, LR. Http://hi.baidu.com/anorchidwith/blog/item/cac6e30903fca5266a60fb1f.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.