转载:http://blog.sina.com.cn/s/blog_9452251d01019qba.html
转自尘的日志
linux/arch/arm/kernel/head.S是linux内核映像解压后执行的第一个文件。
//PAGE_OFFSET
//PHYS_OFFSET
#define
#define
.section
ENTRY(stext)
msr cpsr_c,
mrc p15,
bl __lookup_processor_type @
movs r10,
//
beq __error_p @
//查询machine
bl __lookup_machine_type @
movs r8,
beq __error_a @
bl __vet_atags
bl __create_page_tables
ldr r13,
adr lr,
//此命令将导致程序段__arm920_setup的执行,后面会将到。
//r10中存放的基地址是从__lookup_processor_type中得到的,如上面movs r10,
ENDPROC(stext)
接下来将对上面遇到的几个程序段展开分析。
__lookup_processor_type
在讲解该程序段之前先来看一些相关知识。
内核做支持的每一种CPU类型都由结构体proc_info_list
该结构体在文件arch/arm/include/asm/procinfo.h中定义:
struct
unsigned
unsigned
unsigned
unsigned
unsigned
const
const
unsigned
const
struct
struct
struct
struct
};
对于arm920来说,其对应结构体在文件
初始化。
.section
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long
PMD_SECT_BUFFERABLE
PMD_SECT_CACHEABLE
PMD_BIT4
PMD_SECT_AP_WRITE
PMD_SECT_AP_READ
.long
PMD_BIT4
PMD_SECT_AP_WRITE
PMD_SECT_AP_READ
b __arm920_setup
鈥︹︹︹︹︹︹︹︹︹︹︹
.section
在链接文件arch/arm/kernel/vmlinux.lds中:
SECTIONS
{
#ifdef
.
#else
.
#endif
.text.head
_stext
_sinittext
*(.text.head)
}
.init
INIT_TEXT
_einittext
__proc_info_begin
*(.proc.info.init)
__proc_info_end
__arch_info_begin
*(.arch.info.init)
__arch_info_end
__tagtable_begin
*(.taglist.init)
__tagtable_end
鈥︹︹︹︹︹︹︹︹︹︹︹
}
所有CPU类型对应的被初始化的proc_info_list结构体都放在__proc_info_begin
和__proc_info_end之间。
__lookup_processor_type:
//r3存储的是标号3的物理地址(由于没有启用mmu,所以当前肯定是物理地址)
adr r3,
//R5=__proc_info_begin,r6=__proc_info_end,r7=标号3处的虚拟地址。
ldmda r3,
sub r3,
add r5,
add r6,
1: ldmia r5,
and r4,
////查看代码和CPU硬件是否匹配(比如想在arm920t上运行为cortex-a8编译的内核?不让!)
teq r3,
beq 2f
//PROC_INFO_SZ
add r5,
//判断是否已经到了结构体proc_info_list存放区域的末尾__proc_info_end,
cmp r5,
blo 1b
//如果没有匹配成功就将r5清零,如果匹配成功r5中放的是该CPU类型对应的结构体//proc_info_list的基地址。
mov r5,
2: mov pc,
ENDPROC(__lookup_processor_type)
3: .long .
__lookup_machine_type
每一个CPU平台都可能有其不一样的结构体,描述这个平台的结构体是machine_desc。
这个结构体在文件arch/arm/include/asm/mach/arch.h中定义:
struct
unsigned
unsigned
鈥︹︹︹︹︹︹︹︹︹︹︹
};
对于平台smdk2410来说其对应machine_desc结构在文件
linux/arch/arm/mach-s3c2410/mach-smdk2410.c中初始化:
MACHINE_START(SMDK2410,
.phys_io =
.io_pg_offst =
.boot_params =
.map_io =
.init_irq =
.init_machine =
.timer =
MACHINE_END
对于宏MACHINE_START在文件arch/arm/include/asm/mach/arch.h中定义:
#define
static
.nr =
.name =
#define
};
__attribute__((__section__(".arch.info.init")))表明该结构体在并以后存放的位置。
在链接文件链接脚本文件arch/arm/kernel/vmlinux.lds中
SECTIONS
{
#ifdef
.
#else
.
#endif
.text.head
_stext
_sinittext
*(.text.head)
}
.init
INIT_TEXT
_einittext
__proc_info_begin
*(.proc.info.init)
__proc_info_end
__arch_info_begin
*(.arch.info.init)
__arch_info_end
鈥︹︹︹︹︹︹︹︹︹︹︹
}
在__arch_info_begin和
3: .long .
__lookup_machine_type:
adr r3,
////R4=标号3处的虚拟地址,r5=__arch_info_begin,r6=__arch_info_end。
ldmia r3,
sub r3,
add r5,
add r6,
//读取machine_desc结构的nr参数,对于smdk2410来说该值是MACH_TYPE_SMDK2410。
//这个值在文件linux/arch/arm/tools/mach-types中:
//smdk2410 ARCH_SMDK2410 SMDK2410 193
1: ldr r3,
teq r3,
beq 2f //如果匹配成功就返回
add r5,
cmp r5,
blo 1b
mov r5,
2: mov pc,
ENDPROC(__lookup_machine_type)
__vet_atags
关于参数链表:
内核参数链表的格式和说明可以从内核源代码目录树中的
找到,参数链表必须以ATAG_CORE
ATAG_NONE是各个参数的标记,本身是一个32位值,例如:ATAG_CORE=0x54410001。
其它的参数标记还包括:
ATAG_COMDLINE
数链表。参数结构体的定义如下:
struct tag_ramdisk
struct tag_initrd
struct tag_revision
struct tag_memclk
};
参数结构体包括两个部分,一个是
tag_header结构体的定义如下:
};
其中
tag_header的大小加上
size=(sizeof(tag->tag_header)+sizeof(tag->u.core))>>2,一般通过函数
来获得每个参数结构体的
等。
__vet_atags:
tst r2,
bne 1f
ldr r5,
//#define
subs r5,
bne 1f
ldr r5,
ldr r6,
cmp r5,
bne 1f
mov pc,
1: mov r2,
mov pc,
ENDPROC(__vet_atags)
__create_page_tables
.macro pgtbl,
ldr \rd,
.endm
__create_page_tables:
//r4
//这个值必须是16K对齐的。
pgtbl r4
//为内核代码存储区域创建页表,首先将内核起始地址-0x4000到内核起始地址之间的16K
mov r0,
mov r3,
add r6,
1: str r3,
str r3,
str r3,
str r3,
teq r0,
bne 1b
//从proc_info_list结构中获取字段__cpu_mm_mmu_flags,该字段包含了存储空间访问权限
//等。此处指令执行之后r7=0x00000c1e
ldr r7,
mov r6,
orr r3,
str r3,
add r0,
str r3,
ldr r6,
add r0,
add r6,
1: cmp r0,
add r3,
strls r3,
bls 1b
#ifdef
//如果是XIP就进行以下映射,这只是将内核代码存储的空间重新映射,
orr r3,
.if (KERNEL_RAM_PADDR
orr r3,
.endif
add r0,
str r3,
ldr r6,
add r0,
add r6,
1: cmp r0,
add r3,
strls r3,
bls 1b
#endif
//r0
add r0,
orr r6,
.if (PHYS_OFFSET
orr r6,
.endif
str r6,
#ifdef
ldr r7,
ldr r3,
add r0,
rsb r3,
cmp r3,
movhi r3,
add r6,
ldr r3,
orr r3,
1: str r3,
add r3,
teq r0,
bne 1b
#if
add r0,
orr r3,
str r3,
#endif
#ifdef
add r0,
orr r3,
str r3,
add r0,
str r3,
#endif
#endif
mov pc,
ENDPROC(__create_page_tables)
__arm920_setup
在上面程序段.section
ldr r13,
@
adr lr,
add pc,
R10中存放的是在函数__lookup_processor_type中成功匹配的结构体proc_info_list。
对于arm920来说在文件linux/arch/arm/mm/proc-arm920.S中有:
.section
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long
PMD_SECT_BUFFERABLE
PMD_SECT_CACHEABLE
PMD_BIT4
PMD_SECT_AP_WRITE
PMD_SECT_AP_READ
.long
PMD_BIT4
PMD_SECT_AP_WRITE
PMD_SECT_AP_READ
b __arm920_setup
鈥︹︹︹︹︹︹︹︹︹︹︹
add pc,
.type __arm920_setup,
__arm920_setup:
mov r0,
mcr p15,
mcr p15,
#ifdef
mcr p15,
#endif
adr r5,
ldmia r5,
mrc p15,
//通过查看arm920_crval的值可知该行是清除r0中相关位,为以后对这些位的赋值做准备
bic r0,
orr r0,
mov pc,
.size __arm920_setup,
.type arm920_crval,
arm920_crval:
crval clear=0x00003f3f,
文件linux/arch/arm/kernel/head.S中
__enable_mmu:
#ifdef
orr r0,
#else
bic r0,
#endif
#ifdef
bic r0,
#endif
#ifdef
bic r0,
#endif
#ifdef
bic r0,
#endif
mov r5,
mcr p15,
mcr p15,
b __turn_mmu_on
ENDPROC(__enable_mmu)
文件linux/arch/arm/kernel/head.S中
__turn_mmu_on:
mov r0,
mcr p15,
mrc p15,
mov r3,
mov r3,
mov pc,
ENDPROC(__turn_mmu_on)
在前面有过这样的指令操作ldr r13,
mov pc,
在文件linux/arch/arm/kernel/head-common.S中:
.type __switch_data,
__switch_data:
.long __mmap_switched
.long __data_loc @
.long _data @
.long __bss_start @
.long _end @
.long processor_id @
.long __machine_arch_type @
.long __atags_pointer @
.long cr_alignment @
.long init_thread_union
鈥︹︹︹︹︹︹︹︹︹
.bss
__bss_start
*(.bss)
*(COMMON)
_end
}
鈥︹︹︹︹︹︹︹︹︹︹︹
}
init_thread_union
00033:
00034:
00035:
*/
__mmap_switched:
adr r3,
ldmia r3!,
cmp r4,
1: cmpne r5,
ldrne fp,
strne fp,
bne 1b
mov fp,
1: cmp r6,
strcc fp,
bcc 1b
ldmia r3,
str r9,
str r1,
str r2,
bic r4,
stmia r7,
b start_kernel
ENDPROC(__mmap_switched)