内核干了什么:处理u-boot 传进来的参数———-到识别根文件系统,运行其中的应用程序。
u-boot在内存中设置了一大堆参数,然后通过函数指针theKernel传递给内核,第二个参数为机器ID,第三个为内存中参数存放的地址。
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
1、内核第一个执行的文件:linux/arch/arm/kernel/head.S
主要调用__lookup_processor_type和__lookup_machine_type判断当前内核是否支持CPU和开发板。id由U-Boot传过来,之后再进行创建页表等一些工作。创建页表之后才使用虚拟地址。最后跳到init/main.c中的secondary_start_kernel
ENTRY(stext)
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE//进入管理模式,禁止中断
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
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'
bl __create_page_tables
......
b secondary_start_kernel
2、CPU信息结构定义在:include/asm-arm/procinfo.h,这是每个CPU的信息结构
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;
};
内核对每个开发板都使用宏MACHINE_START、MACHINE_END来定义一个结构,
位于:/include/asm-arm/mach/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 \
};
3、每个CPU具体信息在:arch/arm/mm下对应没一个文件。如proc-arm920.S
//.section表示下面__arm920_proc_info定义在.proc.info.init段,所有CPU信息都连接在该段。
.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
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
.long cpu_arm920_name
.long arm920_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
.long arm920_cache_fns
#else
.long v4wt_cache_fns
#endif
.size __arm920_proc_info, . - __arm920_proc_info
每个开发板对应一个文件如:arch/arm/mach-s3c2440/mach-smdk2440.c,
所有开发板信息位于.arch.info.init段,即位于__arch_info_begin 和 __arch_info_end
之间。U-Boot调用内核时会在r1寄存器中给出机器 ID。
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.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
4、__lookup_processor_type和__lookup_machine_type位于arch/arm/kernel/head-commom.S
//__lookup_processor_type就是在存储各种CPU信息的段之间,即__arch_info_begin和
__arch_info_end之间寻找有没有传入的我们需要的CPU
//以数字当标号,跳转时如2b指跳到上一个标号2,2f指跳到下一个标号2
.type __lookup_processor_type, %function
__lookup_processor_type:
adr r3, 3f
ldmda r3, {r5 - r7}
sub r3, r3, r7 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
1: ldmia r5, {r3, r4} @ value, mask
and r4, r4, r9 @ mask wanted bits
teq r3, r4
beq 2f
add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
cmp r5, r6
blo 1b
mov r5, #0 @ unknown processor
2: mov pc, lr
/*
* This provides a C-API version of the above function.
*/
ENTRY(lookup_processor_type)
stmfd sp!, {r4 - r7, r9, lr}
mov r9, r0
bl __lookup_processor_type
mov r0, r5
ldmfd sp!, {r4 - r7, r9, pc}
/*
* Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
* more information about the __proc_info and __arch_info structures.
*/
.long __proc_info_begin
.long __proc_info_end
3: .long .
.long __arch_info_begin
.long __arch_info_end
5、最后跳到init/main.c中的start_kernel
U-Boot传给内核的参数有两类:
调用内核时r1寄存器指定的机器ID,其在引导阶段__lookup_machine_type函数已经用到。
预先存在某个地址的tag列表(内存tag和命令行tag),其将在arch/arm/kernel/setup.c中函数setup_arch进行初步处理。
start_kernel中调用函数setup_arch
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
struct machine_desc *mdesc;
//要是启动时没有传进命令,则使用默认命令
char *from = default_command_line;
setup_processor();
mdesc = setup_machine(machine_arch_type);
machine_name = mdesc->name;
if (mdesc->soft_reboot)
reboot_setup("s");
if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
/*
* If we have the old style parameters, convert them to
* a tag list.
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;
if (mdesc->fixup)
mdesc->fixup(mdesc, tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
parse_tags(tags);
}
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
//如果命令行传进来则解析
parse_cmdline(cmdline_p, from);
paging_init(&meminfo, mdesc);
.......
start_kernel最后会调用
setup_arch(&command_line);//解析u-boot传进的参数
setup_command_line(command_line);
rest_init(还在init/main.c中)
kernel_init
prepare_namespace
mount_root挂接根文件系统
init_post(和prepare_————并列 run_init_process执行应用程序
MTD:内存技术设备
分区在下面代码中写死,u-boot传进来的/dev/mtdblock3就对应其中一个分区
linux-2.6.22.6\arch\arm\plat-s3c24xx\Common-smdk.c
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "Boot Agent",
.size = SZ_16K,
.offset = 0,
},
[1] = {
.name = "S3C2410 flash partition 1",
.offset = 0,
.size = SZ_2M,
},
[2] = {
.name = "S3C2410 flash partition 2",
.offset = SZ_4M,
.size = SZ_4M,
},
[3] = {
.name = "S3C2410 flash partition 3",
.offset = SZ_8M,
.size = SZ_2M,
},
[4] = {
.name = "S3C2410 flash partition 4",
.offset = SZ_1M * 10,
.size = SZ_4M,
},
[5] = {
.name = "S3C2410 flash partition 5",
.offset = SZ_1M * 14,
.size = SZ_1M * 10,
},
[6] = {
.name = "S3C2410 flash partition 6",
.offset = SZ_1M * 24,
.size = SZ_1M * 24,
},
[7] = {
.name = "S3C2410 flash partition 7",
.offset = SZ_1M * 48,
.size = SZ_16M,
}
};