arm-linux启动,linux启动流程arm

linux启动分析(1)---bootloader启动内核过程

void (*startkernel)(int zero, int arch, unsigned int params_addr) = (void(*)(int, int, unsigned int))KERNEL_RAM_BASE;

其中KERNEL_RAM_BASE为内核在ram中启动的地址,ARCH_NUMBER是Machine Type Number,kernel_params_start是参数在ram的偏移地址。

linux启动分析(2)---内核启动地址的确定

其中TEXTADDR就是内核启动的虚拟地址,定义在kernel/arch/arm/Makefile中:ifeq ($(CONFIG_CPU_32),y)

PROCESSOR    = armv

TEXTADDR     = 0xC0008000

LDSCRIPT     = arch/arm/vmlinux-armv.lds.in

endif

内核编译链接过程是依靠vmlinux.lds文件,以arm为例vmlinux.lds文件位于kernel/arch/arm/vmlinux.lds,但是该文件是由vmlinux-armv.lds.in生成的,根据编译选项的不同源文件还可以是vmlinux-armo.lds.in,vmlinux-armv-xip.lds.in。

vmlinux-armv.lds.in文件的内容:

OUTPUT_ARCH(arm)

ENTRY(stext)

SECTIONS

{

. = TEXTADDR;

.init : {           /* Init code and data       */

_stext = .;

__init_end = .;

}

一般情况下都在生成vmlinux后,再对内核进行压缩成为zImage,压缩的目录是kernel/arch/arm/boot。下载到flash中的是压缩后的zImage文件,zImage是由压缩后的vmlinux和解压缩程序组成,如下图所示:

linux启动分析(3)---内核解压缩过程

它将调用函数decompress_kernel(),这个函数在文件arch/arm/boot/compressed/misc.c中,decompress_kernel()又调用proc_decomp_setup(),arch_decomp_setup()进行设置,然后使用在打印出信息“Uncompressing Linux...”后,调用gunzip()。将内核放于指定的位置。

linux启动分析(4)---汇编启动 arch/arm/kernel/head.S

__HEAD

ENTRY(stext)

setmode    PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode

@ and irqs disabled

mrc    p15, 0, r9, c0, c0        @ get processor id

bl    __lookup_processor_type        @ r5=procinfo r9=cpuid

movs    r10, r5                @ invalid processor (r5=0)?

THUMB( it    eq )        @ force fixup-able long branch encoding

beq    __error_p            @ yes, error 'p'

#ifndef CONFIG_XIP_KERNEL

adr    r3, 2f

ldmia    r3, {r4, r8}

sub    r4, r3, r4            @ (PHYS_OFFSET - PAGE_OFFSET)

add    r8, r8, r4            @ PHYS_OFFSET

#else

ldr    r8, =PLAT_PHYS_OFFSET

#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

/*

* 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

ARM(    add    pc, r10, #PROCINFO_INITFUNC    )

THUMB(    add    r12, r10, #PROCINFO_INITFUNC    )

THUMB(    mov    pc, r12                )

1:    b    __enable_mmu

ENDPROC(stext)

head-common.S

__INIT

__mmap_switched:

adr    r3, __mmap_switched_data

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

ARM(    ldmia    r3, {r4, r5, r6, r7, sp})

THUMB(    ldmia    r3, {r4, r5, r6, r7}    )

THUMB(    ldr    sp, [r3, #16]        )

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)

__lookup_processor_type

__lookup_architecture_type

__create_page_tables

__mmap_switched

b   start_kernel

linux启动分析(5)---C程序入口函数start_kernel

init\main.c

asmlinkage void __init start_kernel(void)

{

printk(KERN_NOTICE "%s", linux_banner);

setup_command_line(command_line);

printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);

parse_early_param();

parse_args("Booting kernel", static_command_line, __start___param,

__stop___param - __start___param,

&unknown_bootoption);

console_init();

fork_init(totalram_pages);

rest_init();

}

static noinline void __init_refok rest_init(void)

{

kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

cpu_idle();

}

static int __init kernel_init(void * unused)

{

/* Open the /dev/console on the rootfs, this should never fail */

if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

printk(KERN_WARNING "Warning: unable to open an initial console.\n");

init_post();

return 0;

}

linux启动6 init_post

static noinline int init_post(void)

{

if (execute_command) {

run_init_process(execute_command);

printk(KERN_WARNING "Failed to execute %s.  Attempting "

"defaults...\n", execute_command);

}

run_init_process("/sbin/init");

run_init_process("/etc/init");

run_init_process("/bin/init");

run_init_process("/bin/sh");

panic("No init found.  Try passing init= option to kernel. "

"See Linux Documentation/init.txt for guidance.");

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值