linux启动过程内核head.S

已知条件:
1.首先通过分析Kernel的Makefile的链接知道 之后内核启动执行的第一个脚本是:../../arch/arm/kernel/head.S
2.u-boot启动内核:theKernel(0,bd->bi_arch_number,bd->bi_boot_params)
bd->bi_arch_number  //机器id

bd->bi_boot_params  //参数存放的地址


分析:head.S:
@ 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)?
beq __error_p @ yes, error 'p'
bl __lookup_machine_type @ r5=machinfo  //查找机器ID
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'

bl__create_page_tables


找到 __lookup_machine_type

head-common.S:


3: #3b地址定义
.long  .   
.long  __arch_info_begin
.long  __arch_info_end

__lookup_machine_type:
adr r3, 3b #r3 = 3b的物理地址
ldmia r3, {r4, r5, r6} # r4= 3 . 的虚拟地址  r5=__arch_info_begin r6 = __arch_info_end
subr3, r3, r4       @ get offset between virt&phys #寻找__arch_info_begin物理地址
add r5, r5, r3       @ convert virt addresses to ##寻找__arch_info_end物理地址
add r6, r6, r3       @ physical address space

1: 

ldr r3, [r5, #MACHINFO_TYPE] @ get machine type

teq r3, r1 @ matches loader number?
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine

2: 

mov pc, lr


问:__arch_info_begin,__arch_info_end 在哪儿定义的?
vmlinux.lds:
  ......
  __arch_info_begin=.;
  *(.arch.info.init) //这是代码中定义的一个段

  __arch_info_end=.;


使用sourceInsight来搜索一下.arch.info.init
  arch.h

 

 #define MACHINE_START(_type,_name) \

  static const struct machine_desc __mach_desc_##_type\
   __used \
   __attribute__((__section__(".arch.info.init"))) = {\
.nr = MACH_TYPE_##_type,\
.name = _name,
   #define MACHINE_END \
   };


谁在使用这个宏:以s3c2440为例:

MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <[email protected]> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,

.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END


将其展开:
static const struct machine_desc __mach_desc_S3C2440 = {
.nr = MACH_TYPE_S3C2440,
.name = "SMDK2440",
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
};

machine_desc 打开这个结构体
描述一个单板的属性:
struct machine_desc {
unsigned int nr; /* architecture number*/
unsigned int phys_io; /* start of physical io*/
unsigned int io_pg_offst; /* byte offset for io * page tabe entry*/


const char *name; /* architecture name*/ 机器id
unsigned long boot_params; /* tagged list*/ 参数


unsigned int video_start; /* start of video RAM*/
unsigned int video_end; /* end of video RAM*/


unsigned int reserve_lp0 :1; /* never has lp0*/
unsigned int reserve_lp1 :1; /* never has lp1*/
unsigned int reserve_lp2 :1; /* never has lp2*/
unsigned int soft_reboot :1; /* soft reboot*/
void (*fixup)(struct machine_desc *,
struct tag *, char **,
struct meminfo *);
void (*map_io)(void);/* IO mapping function*/
void (*init_irq)(void);
struct sys_timer*timer; /* system tick timer*/
void (*init_machine)(void);
};


在看看head_common.S

1:

ldrr3, [r5, #MACHINFO_TYPE] @ get machine type

 teq r3, r1 @ matches loader number? 比较机器id


比较成功之后:
     bl __create_page_tables   @#创建页表
     ldr r13, __switch_data @ address to jump to after
         @ mmu has been enabled
     adr lr, __enable_mmu @ return (PIC) address  #使能MMU
     add pc, r10, #PROCINFO_INITFUNC
创建页表,使能MMU之后跳转到__switch_data
 __switch_data:
.long __mmap_switched
.long __data_loc @ r4
.long __data_start @ r5
.long __bss_start @ r6
.long _end @ r7
.long processor_id @ r4
.long __machine_arch_type @ r5
.long cr_alignment @ r6
.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
 *  r9  = processor ID
 */
.type __mmap_switched, %function
__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, sp}
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
bic r4, r0, #CR_A @ Clear 'A' bit
stmia r6, {r0, r4} @ Save control register values
b start_kernel    #启动内核 内核的第一个C函数:
总结:head.s的作用
1、判断kernel支持不支持CPU
2、判断kernel支持不支持Board
3、建立页表

4、使能MMU

5、清BSS

5、跳转到 start_kernel

你可能感兴趣的:(linux,kernel)