ARMv7:Linux Kernel引导 <1>

本文深入探讨内核启动过程,从压缩内核镜像的解压缩开始,直至内核通过head.S文件初始化并启用MMU。详细解析了关键步骤,包括ARM环境下的指令执行、内存映射初始化、以及核心参数的加载与设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.如果内核镜像是压缩的,需要解压缩,引导的第一步是从解压缩开始:arch\arm\boot\compressed\head.S

2.解压缩之后,内核镜像已经存在于ARM中了,下面开始运行,内核开始运行是从/arch/arm/kernel/head.S开始的,入口代码为:

1
2
3
4
5
6
7
8
     .arm
     __HEAD
ENTRY(stext)
                        
  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:           )

这是由/arch/arm/kernel/vmlinux.lds.S决定的。告诉我们入口点为stext.

1
2
OUTPUT_ARCH(arm)
ENTRY(stext)

3.顺序执行head.S的代码。

1
2
3
4
5
6
7
8
  ldr r13, =__switch_data          @ 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
  ARM(   add pc, r10, #PROCINFO_INITFUNC )
  THUMB( add r12, r10, #PROCINFO_INITFUNC    )
  THUMB( mov pc, r12             )
1:  b   __enable_mmu

代码line1将__switch_data的地址赋给r13,在__enable_mmu(代码line8)执行成功后跳转到__switch_data执行。

因为是.arm环境,所以执行代码ARM(   add pc, r10, #PROCINFO_INITFUNC ),即跳转到__cpu_flush执行。

1
2
3
4
/arch/arm/kernel/head.S 
mrc p15, 0, r9, c0, c0      @ get processor id
bl  __lookup_processor_type     @ r5=procinfo r9=cpuid
movs    r10, r5             @ invalid processor (r5=0)?

r10中保存的是proc_info结构体的start address.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
arch\arm\include\asm\Procinfo.h
struct  proc_info_list {
     unsigned  int         cpu_val;
     unsigned  int         cpu_mask;
     unsigned  long        __cpu_mm_mmu_flags;  /* used by head.S */
     unsigned  long        __cpu_io_mmu_flags;  /* used by head.S */
     unsigned  long        __cpu_flush;         /* used by head.S */
     const  char       *arch_name;
     const  char       *elf_name;
     unsigned  int         elf_hwcap;
     const  char       *cpu_name;
     struct  processor    *proc;
     struct  cpu_tlb_fns  *tlb;
     struct  cpu_user_fns *user;
     struct  cpu_cache_fns    *cache;
};
1
2
include/generated/asm-offsets.h
#define PROCINFO_INITFUNC 16

4.__cpu_flush

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
arch/arm/mm/proc-v7.S
             
__v7_ca9mp_proc_info:
     . long    0x410fc090
     . long    0xff0ffff0
     __v7_proc __v7_ca9mp_setup
                 
                 
     .macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0
     ALT_SMP(. long    PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
             PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags)
     ALT_UP(. long     PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
             PMD_SECT_AF | PMD_FLAGS_UP | \mm_mmuflags)
     . long    PMD_TYPE_SECT | PMD_SECT_AP_WRITE | \
         PMD_SECT_AP_READ | PMD_SECT_AF | \io_mmuflags
     W(b)    \initfunc
             
         
__v7_ca5mp_setup:
__v7_ca9mp_setup:
     mov r10, #(1 << 0)            @ TLB ops broadcasting
     b   1f
__v7_ca7mp_setup:
__v7_ca15mp_setup:
     mov r10, #0

不同架构的CPU,针对的文件不同,对于ARMV7架构的cpu而言,对应的为proc-v7.S。从code中可以看出,其对应俄proc_info为__v7_ca9mp_proc_info,所以偏移16后,就是执行跳转代码    b   1f。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
     __CPUINIT
        
/*
  *  __v7_setup
  *
  *  Initialise TLB, Caches, and MMU state ready to switch the MMU
  *  on.  Return in r0 the new CP15 C1 control register setting.
  *
  *  This should be able to cover all ARMv7 cores.
  *
  *  It is assumed that:
  *  - cache type register is implemented
  */
__v7_ca5mp_setup:
__v7_ca9mp_setup:
     mov r10, #(1 << 0)            @ TLB ops broadcasting
     b   1f
__v7_ca7mp_setup:
__v7_ca15mp_setup:
     mov r10, #0
1:
#ifdef CONFIG_SMP
     ALT_SMP(mrc p15, 0, r0, c1, c0, 1)
     ALT_UP(mov  r0, #(1 << 6))        @ fake it  for  UP
     tst r0, #(1 << 6)         @ SMP/nAMP mode enabled?
     orreq   r0, r0, #(1 << 6)     @ Enable SMP/nAMP mode
     orreq   r0, r0, r10         @ Enable CPU-specific SMP bits
     mcreq   p15, 0, r0, c1, c0, 1
#endif
__v7_setup:

5.__v7_setup->__enable_mmu->__turn_mmu_on

1
2
3
4
5
6
7
8
__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)

r13保存的是__switch_data的地址,mov pc,r13跳转到__switch_data.

6.__mmap_switched

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
     .type   __switch_data, %object
__switch_data:
     . long    __mmap_switched
     . long    __data_loc          @ r4
     . long    _data               @ 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 following fragment of code is executed with the MMU on in MMU mode,
  * and uses absolute addresses; this is not position independent.
  *
  *  r0  = cp#15 control register
  *  r1  = machine ID
  *  r2  = atags pointer
  *  r9  = processor ID
  */
__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)

7. start_kernel, 第一个C语言函数。


原文地址:http://hi.baidu.com/wesley2012/item/dcf2cfc1b9deec14b67a24d9

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值