(9) 调用文件misc.c的函数decompress_kernel(),解压内核于缓存结束的地
方(r2地址之后)。此时各寄存器值有如下变化:
r0为解压后kernel的大小
r4为kernel执行时的地址
r5为解压后kernel的起始地址
r6为CPU类型值(processor ID)
r7为系统类型值(architecture ID)
(10) 将reloc_start代码拷贝之kernel之后(r5+r0之后),首先清除缓存,而
后执行reloc_start。
(11) reloc_start将r5开始的kernel重载于r4地址处。
(12) 清除cache内容,关闭cache,将r7中architecture ID赋于r1,执行
r4开始的kernel代码。
5) 我们在内核启动的开始都会看到这样的输出
Uncompressing Linux...done, booting the kernel.
这也是由decompress_kernel函数内部输出的,它调用了putc()输出字符串,
putc是在#/include/asm-arm/arch-pxa/uncompress.h中实现的。执行完解压过
程,再返回到#/arch/arm/boot/compressed/head.S中,启动内核:
call_kernel: bl cache_clean_flush
bl cache_off
mov r0, #0
mov r1, r7 @ restore architecture number
mov pc, r4 @ call kernel
6) 执行zImage 镜像,到start_kernel( )
整个arm linux内核的启动可分为三个阶段:第一阶段主要是进行cpu和
体系结构的检查、cpu本身的初始化以及页表的建立等;第一阶段的初始化是从
内核入口(ENTRY(stext))开始到start_kernel前结束。这一阶段的代码
在/arch/arm/kernel/head.S中。/arch/arm/kernel/head.S用汇编代码完成,
是内核最先执行的一个文件。这一段汇编代码的主要作用,是检查cpu
id,architecture number,初始化页表、cpu、bbs等操作,并跳到
start_kernel函数。它在执行前,处理器的状态应满足:
r 0 - should be 0
r1 - unique architecture number
MMU - off
I-cache - on or off
D-cache – off
a) 流程图
b) 代码详细注释
#/arch/arm/kernel/head.S
/*
* 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.
*/
#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
#error KERNEL_RAM_VADDR must start at 0xXXXX8000
#endif
.globl swapper_pg_dir
.equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
.macro pgtbl, rd
ldr /rd, =(KERNEL_RAM_PADDR - 0x4000)
.endm
/*
* Since the page table is closely related to the kernel start
address, we
* can convert the page table base address to the base address of the
section
* containing both.
*/
.macro krnladr, rd, pgtable, rambase
bic /rd, /pgtable, #0x000ff000
.endm
/*
/*
* 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 pointer.
*
* See linux/arch/arm/tools/mach-types for the complete list of
machine
* numbers for r1.
*/
.section ".text.head", "ax"
.type stext, %function
ENTRY(stext) //内核入口点
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
//程序状态,禁止FIQ、IRQ,设定Supervisor模式。0b11010011
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cupid //跳转到
判断
//cpu类型,查找运行的cpu的id值和此linux编译支持的id值是否有相
等
movs r10, r5 @ invalid processor (r5=0)?
beq __error_p @ yes, error 'p'
bl __lookup_machine_type @ r5=machinfo
//跳转到判断体系类型,看r1寄存器的architecture number值是否支持。
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'
bl __vet_atags
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_machine_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, __switch_data @ address to jump to after
@ mmu has been enabled
adr lr, __enable_mmu @ return (PIC) address //lr=0xc0028054
add pc, r10, #PROCINFO_INITFUNC
@ initialise processor //r10:pointer to processor
structure
#/arch/arm/kernel/head-common.S
*/
#define ATAG_CORE 0x54410001
#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
.type __switch_data, %object
__switch_data:
.long __mmap_switched
.long __data_loc @ r4
.long __data_start @ r5
.long __bss_start @ r6