Linux Kernel Startup Process Analysis (2)

Source: Internet
Author: User

. 4 _ create_page_tables ()

The _ create_page_tables () function is also located in arch/ARM/kernel/head. S. The Code is as follows:

_ Create_page_tables:

Pgtbl R4 @ page table address

/*

* Clear the 16 K Level 1 Swapper page table

*/

MoV r0, r4

MoV R3, #0

Add R6, R0, #0X4000

1: Str R3, [R0], #4

STR R3, [R0], #4

STR R3, [R0], #4

STR R3, [R0], #4

TEQ r0, R6

BNE 1b

LDR R7, [R10, # procinfo_mm_mmuflags] @ mm_mmuflags

/*

* Create identity mapping for first MB of kernel

* Cater for the MMU enable. This identity mapping

* Will be removed by paging_init (). We use our current program

* Counter to determine corresponding section base address.

*/

MoV R6, PC, LSR #20 @ start of kernel Section

ORR R3, R7, R6, LSL #20 @ flags + kernel Base

STR R3, [R4, R6, LSL #2] @ identity mapping

/*

* Now setup the pagetables for our kernel direct

* Mapped region.

*/

Add r0, R4, # (kernel_start & 0xff000000)> 18

STR R3, [r0, # (kernel_start & 0x00f00000)> 18]!

LDR R6, = (kernel_end-1)

Add r0, R0, #4

Add R6, R4, R6, LSR #18

1: CMP r0, R6

Add R3, R3, #1 <20

Strls R3, [R0], #4

20171b

# Ifdef config_xip_kernel

/*

* Map some Ram to cover our. Data and. BSS areas.

*/

ORR R3, R7, # (kernel_ram_paddr & 0xff000000)

. If (kernel_ram_paddr & 0x00f00000)

ORR R3, R3, # (kernel_ram_paddr & 0x00f00000)

. Endif

Add r0, R4, # (kernel_ram_vaddr & 0xff000000)> 18

STR R3, [r0, # (kernel_ram_vaddr & 0x00f00000)> 18]!

LDR R6, = (_ end-1)

Add r0, R0, #4

Add R6, R4, R6, LSR #18

1: CMP r0, R6

Add R3, R3, #1 <20

Strls R3, [R0], #4

20171b

# Endif

/*

* Then map first 1 MB of RAM in case it contains our boot Params.

*/

Add r0, R4, # page_offset> 18

ORR R6, R7, # (phys_offset & 0xff000000)

. If (phys_offset & 0x00f00000)

ORR R6, R6, # (phys_offset & 0x00f00000)

. Endif

STR R6, [R0]

# Ifdef config_debug_ll

LDR R7, [R10, # procinfo_io_mmuflags] @ io_mmuflags

/*

* Map in Io space for serial debugging.

* This allows debug messages to be output

* Via a serial console before paging_init.

*/

LDR R3, [R8, # machinfo_pgoffio]

Add r0, R4, r3

RSB R3, R3, #0X4000 @ ptrs_per_pgd * sizeof (long)

CMP R3, #0x0800 @ limit to 512 MB

Movhi R3, #0x0800.

Add R6, R0, r3

LDR R3, [R8, # machinfo_physio]

ORR R3, R3, r7

1: Str R3, [R0], #4

Add R3, R3, #1 <20

TEQ r0, R6

BNE 1b

# If defined (config_arch_netwinder) | defined (config_arch_cats)

/*

* If we're using the netwinder or cats, we also need to map

* In the 16550-type serial port for the debug messages

*/

Add r0, R4, #0xff000000> 18

ORR R3, R7, #0x7c000000

STR R3, [R0]

# Endif

# Ifdef config_arch_rpc

Add r0, R4, #0x02000000> 18

ORR R3, R7, #0x02000000

STR R3, [R0]

Add r0, R4, #0xd8000000> 18

STR R3, [R0]

# Endif

# Endif

MoV PC, LR

Endproc (_ create_page_tables)

This code is used to create a level-1 page table. This initial page table is used for the kernel code to be run next. Because the kernel code uses virtual addresses, we must establish MMU before use. Here, MMU only needs to create a page table to identify the virtual address of the kernel code, that is, from kernel_start to kernel_end.

# Define kernel_ram_vaddr (page_offset + text_offset)

# Define kernel_ram_paddr (phys_offset + text_offset)

# If (kernel_ram_vaddr & 0 xFFFF )! = 0x8000

# Error kernel_ram_vaddr must start at 0xxxxx8000

# Endif

. Globl swapper_pg_dir

. Equ swapper_pg_dir, kernel_ram_vaddr-0X4000

. Macro pgtbl, RD

LDR \ RD, = (kernel_ram_paddr-0X4000)

. Endm

# Ifdef config_xip_kernel

# Define kernel_start xip_virt_addr (config_xip_phys_addr)

# Define kernel_end _ edata_loc

# Else

# Define kernel_start kernel_ram_vaddr

# Define kernel_end _ end

# Endif

From the code above, we can see that kernel_start is c0008000, and kernel_end is equal to _ end. _ End we can find traces from vmlinux. LDS. S.

In addition, the MMU page table created here is a level-1 page table, which is in the unit of 1 MB. The level-2 page table (4 K) is not created here. The conversion relationships between ARM Level 1 page tables are as follows:

It can be seen that the content of the level-1 page table descriptor is composed of the physical address segment (the first 12 digits of the physical address) and some MMU management bits; the first-level page table descriptor address is composed of the base address (31-14 bits) of the page table address and the first 12 bits (31-20) of the virtual address. The last two bits are zero, supports 32-bit address alignment.

The process of creating a level-1 page table is to fill in each level-1 page table Descriptor (1 MB) to the address of each level-1 page table descriptor.

1.5 _ enable_mmu ()

After creating a page table, the following code is provided:

LDR R13, _ switch_data @ address to jump to after

@ MMU has been enabled

Adr lr, _ enable_mmu @ return (PIC) Address

Add PC, R10, # procinfo_initfunc

The last sentence is to jump to the processor initialization function execution. Our processor is armv6, so the processor initialization function can be found in arch/ARM/MM/pro_v6.s:

Entry (cpu_v6_proc_init)

MoV PC, LR

OK. Now we know that the purpose is to jump to the _ enable_mmu () function execution. As for R13, he can also use it at the end of the _ enable_mmu () function.

After creating a level-1 page table, we can open MMU and use the virtual address with confidence. The code for enabling MMU is as follows:

_ Enable_mmu:

# Ifdef config_alignment_trap

ORR r0, R0, # cr_a

# Else

Bic r0, R0, # cr_a

# Endif

# Ifdef config_cpu_dcache_disable

Bic r0, R0, # cr_c

# Endif

# Ifdef config_cpu_bpredict_disable

Bic r0, R0, # cr_z

# Endif

# Ifdef config_cpu_icache_disable

Bic r0, R0, # cr_ I

# Endif

MoV R5, # (domain_val (domain_user, domain_manager) | \

Domain_val (domain_kernel, domain_manager) | \

Domain_val (domain_table, domain_manager) | \

Domain_val (domain_io, domain_client ))

MCR P15, 0, R5, C3, C0, 0 @ load domain access register

MCR P15, 0, R4, C2, C0, 0 @ load page table pointer

B _ turn_mmu_on

Endproc (_ enable_mmu)

_ Turn_mmu_on:

MoV r0, R0

MCR P15, 0, R0, C1, C0, 0 @ write control Reg

MRC P15, 0, R3, C0, C0, 0 @ read ID Reg

MoV R3, r3

MoV R3, r3

MoV PC, R13

Endproc (_ turn_mmu_on)

This code is very simple: Put the base address of the first-level page table in C2 of CP15, and then open MMU. At the end of the execution, assign R13 to the PC, that is, jump to _ swtich_data and execute it.

1.6 _ mmap_switched ()

We can find the _ switch_data definition in arch/ARM/kernel/head-common.S:

_ Switch_data:

. Long _ mmap_switched

. Long _ data_loc @ r4

. Long _ data_start @ R5

. Long _ bss_start @ R6

. Long _ end @ r7

. Long processor_id @ r4

. Long _ machine_arch_type @ R5

. Long _ atags_pointer @ R6

. Long cr_alignment @ r7

. Long init_thread_union + thread_start_sp @ sp

The visible value of _ switch_data is equivalent to the pointer address of the _ mmap_switched () function. The _ mmap_switch () function is defined as follows:

_ Mmap_switched:

ADR R3, _ switch_data + 4

Ldmia R3 !, {R4, R5, R6, R7}

CMP R4, R5 @ copy data segment if needed

1: cmpne R5, R6

Ldrne FP, [R4], #4

Strne FP, [R5], #4

BNE 1b

MoV FP, #0 @ clear BSS (and zero FP)

1: CMP R6, r7

Strcc FP, [R6], #4

BCC 1b

Ldmia R3, {R4, R5, R6, R7, SP}

STR R9, [R4] @ save processor ID

STR R1, [R5] @ save Machine Type

STR R2, [R6] @ save atags pointer

Bic R4, R0, # cr_a @ clear 'A' bit

Stmia R7, {r0, R4} @ save control register values

B start_kernel

Endproc (_ mmap_switched)

This code is very simple, that is, copying data to the data segment; clearing the BSS; then saving the processor ID, Machine Type and ATAG pointer to the corresponding location of the memory (because the next step is to jump to the C language environment for execution, you must save meaningful registers). Jump to the start_kernel () function to enter the operating system environment.

Related Article

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.