linux/arch/arm/kernel/head.S是linux内核映像解压后执行的第一个文件。
//PAGE_OFFSET = 0xc0000000; TEXT_OFFSET = 0x00008000;
//PHYS_OFFSET = 0x30000000;
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
/*
链接脚本文件arch/arm/kernel/vmlinux.lds指定了编译时程序段存放的位置。
SECTIONS
{
#ifdef CONFIG_XIP_KERNEL
. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
#else
. = PAGE_OFFSET + TEXT_OFFSET;
#endif
.text.head : {
_stext = .;
_sinittext = .;
*(.text.head)
}
.init : {
……………………
}
*/
.section ".text.head", "ax"
ENTRY(stext)
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE //禁止FIQ、IRQ,设定SVC模式
mrc p15, 0, r9, c0, c0 @ 获取 processor id
/*判断CPU类型,查找运行的CPU ID值与Linux编译支持的ID值是否支持 */
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
///*判断如果r10的值为0,跳转到出错处理,*/
beq __error_p @ yes, error 'p'
//查询machine ID并检查合法性
bl __lookup_machine_type @ r5=machinfo
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'
bl __vet_atags //检查bootloader传入的参数列表atags的合法性
bl __create_page_tables //创建初始页表
ldr r13, __switch_data //将列表__switch_data存到r13中后面会跳到该列表出
adr lr, __enable_mmu //将程序段__enable_mmu的地址存到lr中。
//此命令将导致程序段__arm920_setup的执行,后面会将到。
//r10中存放的基地址是从__lookup_processor_type中得到的,如上面movs r10, r5
add pc, r10, #PROCINFO_INITFUNC
ENDPROC(stext)
接下来将对上面遇到的几个程序段展开分析。
__lookup_processor_type
/**********************************************************************/
在讲解该程序段之前先来看一些相关知识。
内核做支持的每一种CPU类型都由结构体proc_info_list 来描述。
该结构体在文件arch/arm/include/asm/procinfo.h中定义:
struct proc_info_list {
unsigned int cpu_val;
unsigned int cpu_mask;
unsigned long __cpu_mm_mmu_flags; /* used by head.S */
unsigned long __cpu_io_mmu_flags; /* used by head.S */
unsigned long __cpu_flush; /* used by head.S */
const char *arch_name;
const char *elf_name;
unsigned int elf_hwcap;
const char *cpu_name;
struct processor *proc;
struct cpu_tlb_fns *tlb;
struct cpu_user_fns *user;
struct cpu_cache_fns *cache;
};
对于arm920来说,其对应结构体在文件 linux/arch/arm/mm/proc-arm920.S中
初始化。
.section ".proc.info.init", #alloc, #execinstr
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long PMD_TYPE_SECT | \
PMD_SECT_BUFFERABLE | \
PMD_SECT_CACHEABLE | \
PMD_BIT4 | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
.long PMD_TYPE_SECT | \
PMD_BIT4 | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
b __arm920_setup
………………………………
.section ".proc.info.init"表明了该结构在编译后存放的位置。
在链接文件arch/arm/kernel/vmlinux.lds中:
SECTIONS
{
#ifdef CONFIG_XIP_KERNEL
. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
#else
. = PAGE_OFFSET + TEXT_OFFSET;
#endif
.text.head : {
_stext = .;
_sinittext = .;
*(.text.head)
}
.init : { /* Init code and data */
INIT_TEXT
_einittext = .;
__proc_info_begin = .;
*(.proc.info.init)
__proc_info_end = .;
__arch_info_begin = .;
*(.arch.info.init)