ARM Linux内核启动(1)

通过分析可知ARM-linux内核的启动分为两个过程,首先,自解压内核到内存中;其次,跳转到解压缩之后的内核运行。压缩内核的启动部分在 linux/arch/arm/boot/compressed/head.S和arch\arm\boot\compressed\misc.c两个文件中。而分压缩内核的启动部分,是真正的linux内核的入口,在linux/arch/arm/kernel/head.S文件中。源码如下:我们一段段的列出:

/*
 * 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.进入时的条件

 *
 * 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.
 */
__INIT
.type stext, #function
ENTRY(stext)
mov r12, r0
mov r0, #PSR_F_BIT | PSR_I_BIT | MODE_SVC@ make sure svc mode确定SVC模式
msr cpsr_c, r0@ and all irqs disabled关闭所有中断
bl __lookup_processor_type跳转到查找处理器函数段
teq r10, #0@ invalid processor?判断是否是无效处理器
moveq r0, #'p'@ yes, error 'p'
beq __error
bl __lookup_architecture_type跳转到查找结构函数段
teq r7, #0@ invalid architecture?
moveq r0, #'a'@ yes, error 'a'
beq __error
bl __create_page_tables建立页表


/*
* 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_architecture_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.
*/注释说的很详细。此时CPU已经准备好打开MMU,r0保存CPU控制寄存器的值
adr lr, __turn_mmu_on@ return (PIC) address
addpc, r10, #12


.type __switch_data, %object
__switch_data:
.long __mmap_switched
.long __data_loc@ r2
.long __data_start@ r3
.long __bss_start@ r4
.long _end@ r5
.long processor_id@ r6
.long __machine_arch_type@ r7
.long cr_alignment@ r8
.long init_thread_union+8192@ sp


/*
 * Enable the MMU.  This completely changes the structure of the visible
 * memory space.  这将完全改变可见存储空间的结构
 */
.align 5
.type __turn_mmu_on, %function
__turn_mmu_on:
ldr lr, __switch_data
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #2@ ...........A.
#endif
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, lr



/*
 * The following fragment of code is executed with the MMU on, and uses
 * absolute addresses; this is not position independent.下面代码在MMU打开的情况下运行,用绝对地址,与位置无关
 *
 *  r0  = processor control register
 *  r1  = machine ID机器ID
 *  r9  = processor ID处理器ID
 *  r12 = value of r0 when kernel was called (currently always zero)
 */

这里主要是为调用c函数start_kernel做准备。
.align 5
__mmap_switched:
adr r2, __switch_data + 4
ldmia r2, {r2, r3, r4, r5, r6, r7, r8, sp}


cmp r2, r3@ Copy data segment if needed
1: cmpne r3, r4
ldrne fp, [r2], #4
strne fp, [r3], #4
bne 1b


mov fp, #0@ Clear BSS (and zero fp)
1: cmp r4, r5
strcc fp, [r4],#4
bcc 1b


str r9, [r6]@ Save processor ID
str r1, [r7]@ Save machine type
bic r2, r0, #2@ Clear 'A' bit
stmia r8, {r0, r2}@ Save control register values
b start_kernel
内核编译连接过程的连接脚本是vmlinux.lds文件,ARM是arch\arm\kernel\vmlinux.lds.S,列出部分,如下所示:

OUTPUT_ARCH(arm)
ENTRY(stext)
#ifndef __ARMEB__
jiffies = jiffies_64;
#else
jiffies = jiffies_64 + 4;
#endif
SECTIONS
{
. = TEXTADDR;内核启动的虚拟地址,为0xc0008000
.init : { /* Init code and data */
_stext = .;
_sinittext = .;
*(.init.text)
_einittext = .;
__proc_info_begin = .;
*(.proc.info)
__proc_info_end = .;
__arch_info_begin = .;
*(.arch.info)
__arch_info_end = .;
__tagtable_begin = .;
*(.taglist)
__tagtable_end = .;
. = ALIGN(16);
__setup_start = .;
*(.init.setup)
__setup_end = .;
__early_begin = .;
*(__early_param)
__early_end = .;
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
__initcall_end = .;
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;
__security_initcall_start = .;
*(.security_initcall.init)
__security_initcall_end = .;
. = ALIGN(32);
__initramfs_start = .;
usr/built-in.o(.init.ramfs)
__initramfs_end = .;
. = ALIGN(64);
__per_cpu_start = .;
*(.data.percpu)
__per_cpu_end = .;
#ifndef CONFIG_XIP_KERNEL
__init_begin = _stext;
*(.init.data)
. = ALIGN(4096);
__init_end = .;
#endif

zImage是由生成的vmlinux再经过压缩生成的,此时的连接脚本是\arch\arm\boot\compressed\vmlinux.lds,内容如下:

 */
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
  . = TEXT_START;内核RAM启动的偏移地址,这个地址是物理地址。

\arch\arm\boot\compressed\Makefile中有如下

SEDFLAGS= s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/使得TEXT_START=ZTEXTADDR。
  _text = .;


  .text : {
    _start = .;
    *(.start)
    *(.text)
    *(.fixup)
    *(.gnu.warning)
    *(.rodata)
    *(.rodata.*)
    *(.glue_7)
    *(.glue_7t)
    *(.piggydata)
    . = ALIGN(4);
  }
这篇先到这里,下篇再说。

ARM Linux内核启动(2)的连接


你可能感兴趣的:(ARM Linux内核启动(1))