历史上的今天
今天是:2025年03月31日(星期一)
2020年03月31日 | ARMv7:Linux Kernel引导
2020-03-31 来源:eefocus
1.如果内核镜像是压缩的,需要解压缩,引导的第一步是从解压缩开始:archarmbootcompressedhead.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 | archarmincludeasmProcinfo.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 推荐阅读
史海拾趣
|




