Linux4.1初始化流程详细注释——第一阶段head.S与head-common.S
- 本文直接展示head.S与head-common.S的源码、编译后的汇编码,并在此基础上增加行注释
- 由于汇编源码中使用的行注释是@,所以此文增加的行注释使用 //
- 内核版本4.1
1)head.S/头文件、宏定义等
/*
* linux/arch/arm/kernel/head.S
*
* Copyright (C) 1994-2002 Russell King
* Copyright (c) 2003 ARM Limited
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Kernel startup code for all 32-bit CPUs
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
#include <asm/cp15.h>
#include <asm/domain.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
#include <asm/memory.h>
#include <asm/thread_info.h>
#include <asm/pgtable.h>
#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING)
#include CONFIG_DEBUG_LL_INCLUDE
#endif
/*
* swapper_pg_dir is the virtual address of the initial page table.
* We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must
* make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect
* the least significant 16 bits to be 0x8000, but we could probably
* relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
*/
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
// PAGE_OFFSET = 0xC0000000
// TEXT_OFFSET = 0x00008000
// KERNEL_RAM_VADDR = 0xC0008000
#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
#error KERNEL_RAM_VADDR must start at 0xXXXX8000
#endif
#ifdef CONFIG_ARM_LPAE // 未定义,所以PG_DIR_SIZE = 0x4000,PMD_ORDER = 2
// PG_DIR_SIZE代表一级也表的大小,2^12个entry,每个entry是4字节,即需要16K(0x4000)空间
// PMD_ORDER代表每个entry是4字节(2^2=4)
/* LPAE requires an additional page for the PGD */
#define PG_DIR_SIZE 0x5000
#define PMD_ORDER 3
#else
#define PG_DIR_SIZE 0x4000
#define PMD_ORDER 2
#endif
.globl swapper_pg_dir
.equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE
// swapper_pg_dir = 0x50004000
.macro pgtbl, rd, phys
add \rd, \phys, #TEXT_OFFSET // rd = phys + 0x8000
sub \rd, \rd, #PG_DIR_SIZE // rd = rd - 0x4000
.endm
2)head.S/stext
/*
* Kernel startup entry point.
* ---------------------------
*
* This is normally called from the decompressor code. The requirements
* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
* r1 = machine nr, r2 = atags or dtb pointer.
*
* This code is mostly position independent, so if you link the kernel at
* 0xc0008000, you call this at __pa(0xc0008000).
*
* See linux/arch/arm/tools/mach-types for the complete list of machine
* numbers for r1.
*
* We're trying to keep crap to a minimum; DO NOT add any machine specific
* crap here - that's what the boot loader (or in extreme, well justified
* circumstances, zImage) is for.
*/
.arm
__HEAD
ENTRY(stext)
ARM_BE8(setend be) @ ensure we are in BE8 mode
THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB( 1: )
#ifdef CONFIG_ARM_VIRT_EXT
bl __hyp_stub_install
#endif
@ ensure svc mode and all interrupts masked
safe_svcmode_maskall r9
mrc p15, 0, r9, c0, c0 @ get processor id
// 获取处理器id,我的是r9 = 0x410fb766
bl __lookup_processor_type @ r5=procinfo r9=cpuid
// r5 = 0x50619e38
movs r10, r5 @ invalid processor (r5=0)?
// r10 = 0x50619e38
THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p @ yes, error 'p'
#ifdef CONFIG_ARM_LPAE // 未定义,跳过
mrc p15, 0, r3, c0, c1, 4 @ read ID_MMFR0
and r3, r3, #0xf @ extract VMSA support
cmp r3, #5 @ long-descriptor translation table format?
THUMB( it lo ) @ force fixup-able long branch encoding
blo __error_lpae @ only classic page table format
#endif
#ifndef CONFIG_XIP_KERNEL // 未定义,不跳过
adr r3, 2f // r3 = 0xc000807c
ldmia r3, {
r4, r8} // r4 = 0xc000807c, r8 = 0xc0000000
sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)
// PHYS_OFFSET = 0x50000000
// PAGE_OFFSET = 0xC0000000
// r4 = 0x90000000
add r8, r8, r4 @ PHYS_OFFSET
// r8 = 0x50000000
#else // 跳过
ldr r8, =PLAT_PHYS_OFFSET @ always constant in this case
#endif
/*
* r1 = machine no, r2 = atags or dtb,
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
bl __vet_atags
#ifdef CONFIG_SMP_ON_UP // 未定义,跳过
bl __fixup_smp
#endif
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
bl __fixup_pv_table
#endif
bl __create_page_tables // 简单初始化MMU页表项,后面还会继续初始化
/*
* The following calls CPU specific code in a position independent
* manner. See arch/arm/mm/proc-*.S for details. r10 = base of
* xxx_proc_info structure selected by __lookup_processor_type
* above. On return, the CPU will be ready for the MMU to be
* turned on, and r0 will hold the CPU control register value.
*/
ldr r13, =__mmap_switched @ address to jump to after
@ mmu has been enabled
adr lr, BSYM(1f) @ return (PIC) address
mov r8, r4 @ set TTBR1 to swapper_pg_dir
ldr r12, [r10, #PROCINFO_INITFUNC]
add r12, r12, r10
ret r12
1: b __enable_mmu
ENDPROC(stext)
.ltorg
#ifndef CONFIG_XIP_KERNEL
2: .long .
.long PAGE_OFFSET
#endif
2.1)编译后的汇编:head.S/stext
包含指令地址,用于与上文对比
c0008000 <stext>:
c0008000: e10f9000 mrs r9, CPSR
c0008004: e229901a eor r9, r9, #26
c0008008: e319001f tst r9, #31
c000800c: e3c9901f bic r9, r9, #31
c0008010: e38990d3 orr r9, r9, #211 ; 0xd3
c0008014: 1a000004 bne c000802c <stext+0x2c>
c0008018: e3899c01 orr r9, r9, #256 ; 0x100
c000801c: e28fe00c add lr, pc, #12
c0008020: e16ff009 msr SPSR_fsxc, r9
c0008024: e12ef30e .word 0xe12ef30e
c0008028: e160006e .word 0xe160006e
c000802c: e121f009 msr CPSR_c, r9
c0008030: ee109f10 mrc 15, 0, r9, cr0, cr0, {
0}
c0008034: eb00051b bl c00094a8 <__lookup_processor_type>
c0008038: e1b0a005 movs sl, r5
c000803c: 0a00053e beq c000953c <__error_p>
c0008040: e28f3034 add r3, pc, #52 ; 0x34
c0008044: e8930110 ldm r3, {
r4, r8}
c0008048: e0434004 sub r4, r3, r4
c000804c: e0888004 add r8, r8, r4
c0008050: eb00005f bl c00081d4 <__vet_atags>
c0008054: eb000049 bl c0008180 <__fixup_pv_table>
c0008058: eb000009 bl c0008084 <__create_page_tables>
c000805c: e59fd014 ldr sp, [pc, #20] ; c0008078 <stext+0x78>
c0008060: e28fe00c add lr, pc, #12
c0008064: e1a08004 mov r8, r4
c0008068: e59ac010 ldr ip, [sl, #16]
c000806c: e08cc00a add ip, ip, sl
c0008070: e1a0f00c mov pc, ip
c0008074: ea00003c b c000816c <__enable_mmu>
c0008078: c058a2e0 .word 0xc058a2e0
c000807c: c000807c .word 0xc000807c
c0008080: c0000000 .word 0xc0000000
3)head.S/__create_page_tables
/*
* Setup the initial page tables. We only setup the barest
* amount which are required to get the kernel running, which
* generally means mapping in the kernel code.
*
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*
* Returns:
* r0, r3, r5-r7 corrupted
* r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
*/
__create_page_tables:
pgtbl r4, r8 @ page table address
// pgtbl是汇编宏,定义在第一节
// r4 = 0x50004000
/*
* Clear the swapper page table
* 0x50004000~0x50007fff物理地址中的数据清零
*/
mov r0, r4 // r0 = 0x50004000
mov r3, #0 // r3 = 0
add r6, r0, #PG_DIR_SIZE // r6 = 0x50008000
1: str r3, [r0], #4 // *(0x50004000) = 0;*(0x50004010) = 0;...
str r3, [r0], #4 // *(0x50004004) = 0;*(0x50004014) = 0