linux内核启动过程分析
来源:互联网 发布:js导致硬件死机 编辑:程序博客网 时间:2024/06/11 06:39
linux内核启动过程分析
1.处理U-boot 传入的参数
在Linux/arch/arm/kernel/head.s中
(1)判断是否支持该CPU(uboot启动时传入的参数bd->bi_arch_number为362)
mrc p15, 0, r9, c0, c0 @ get processor idbl __lookup_processor_type @ r5=procinfo r9=cpuid/*theKernel (0, bd->bi_arch_number, bd->bi_boot_params);*/
g:\linux-2.6.22.6\arch\arm\kernel\head-common.S下
/* * Read processor ID register (CP#15, CR0), and look up in the linker-built * supported processor list. Note that we can't use the absolute addresses * for the __proc_info lists since we aren't running with the MMU on * (and therefore, we are not in the correct address space). We have to * calculate the offset. * * r9 = cpuid * Returns: * r3, r4, r6 corrupted * r5 = proc_info pointer in physical address space * r9 = cpuid (preserved) */ .type __lookup_processor_type, %function__lookup_processor_type: adr r3, 3f /* R3=3f的地址,为实际地址,物理地址 */ ldmda r3, {r5 - r7} /* ldm为加载多个寄存器,DA 每次传送后地址减四,LDMDA指令,每次传送后地址减4,long 型每次占4个字节。r5=__proc_info_begin ,r6=__proc_info_end ,r7="."代表虚拟地址*/ sub r3, r3, r7 @ get offset between virt&phys add r5, r5, r3 @ convert virt addresses to add r6, r6, r3 @ physical address space1: ldmia r5, {r3, r4} @ value, mask/* ldm为加载多个寄存器,iA 每次传送后地址加四*/ 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 processor2: 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_end3: .long . .long __arch_info_begin .long __arch_info_end
在G:\linux-2.6.22.6\arch\arm\kernel\vmlinux.lds.S中
SECTIONS{ ....... . = PAGE_OFFSET + TEXT_OFFSET;/*TEXT_OFFSET=0x00000800*/ ......init : { /* Init code and data */...... __arch_info_begin = .; *(.arch.info.init)/* *表示所有的*/ __arch_info_end = .;
PAGE_OFFSET 在Linux/include/asm-arm/Memory.c下定义
/* * Page offset: 3GB */#ifndef PAGE_OFFSET#define PAGE_OFFSET UL(0xc0000000)#endif
在内核中查找
grep ".arch.info.init" * -nR
在include/asm-arm/mach/arch.h中,
/* * Set of macros to define architecture features. This is built into * a table by the linker. */#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 \};
关于MACHINE_START(_type,_name)的定义在include/configs/100ask24x0.h中
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,/*0x30000100*/ .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\ __used \ __attribute__((__section__(".arch.info.init"))) = { \ .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 结构体在linux/asm-arm/arch/Arch.h中
struct machine_desc { /* * Note! The first four elements are used * by assembler code in head-armv.S */ 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 */ 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);};
(2)判断是否支持该单板
bl __lookup_machine_type @ r5=machinfo
(3)创建页表,由于链接地址是虚拟地址,需要创建页表与实际内存进行对应。
bl __create_page_tables
(4)使能mmu
adr lr, __enable_mmu @ return (PIC) address add pc, r10, #PROCINFO_INITFUNC
(5)跳转到secondary_start_kernel
b secondary_start_kernel
函数在Linux/arch/arm/kernel/smp.c
asmlinkage void __cpuinit secondary_start_kernel(void){}
Linux内核启动的第二阶段在
Linux/init/main.C
主要函数
asmlinkage void __init start_kernel(void){printk(linux_banner);setup_arch(&command_line);/*解析uboot传入的启动参数*/setup_command_line(command_line);/*解析uboot传入的启动参数*/parse_early_param();console_init();....... rest_init();}
在该函数中首先打印内核版本信息,
printk(linux_banner);
设置与体系结构相关的环境
setup_arch(&command_line);/*解析uboot传入的启动参数*/setup_command_line(command_line);/*解析uboot传入的启动参数*/
在arch/arm/kernel/setup.c中
void __init setup_arch(char **cmdline_p){ struct tag *tags = (struct tag *)&init_tags; struct machine_desc *mdesc;/*machine_desc 为前面linux/asm-arm/arch/Arch.h中定义的结构体*/ char *from = default_command_line; setup_processor(); mdesc = setup_machine(machine_arch_type); machine_name = mdesc->name; /*.name = "SMDK2440",*/ if (mdesc->soft_reboot) reboot_setup("s"); if (mdesc->boot_params) tags = phys_to_virt(mdesc->boot_params);/* .boot_params = S3C2410_SDRAM_PA + 0x100,=0x30000100,也是uboot启动的最后theKernel (0, bd->bi_arch_number, bd->bi_boot_params);(uboot/lib_arm/Armlinux.c)告诉内核的存放参数的地址gd->bd->bi_boot_params = 0x30000100(uboot/board/100ask24x0.c);*/
parse_early_param();
该函数同样在Linux/init/main.C下
void __init parse_early_param(void){ static __initdata int done = 0; static __initdata char tmp_cmdline[COMMAND_LINE_SIZE]; if (done) return; /* All fall through to do_early_param. */ strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); parse_args("early options", tmp_cmdline, NULL, 0, do_early_param); done = 1;}
初始化控制台
console_init();
阅读全文
0 0
- linux内核启动过程分析
- linux 内核启动过程分析
- Linux 内核启动过程分析
- Linux内核启动过程分析
- Linux内核启动过程分析
- linux内核启动过程分析
- Linux内核启动过程分析
- Linux内核启动过程分析
- linux内核启动过程分析
- linux内核启动过程分析
- Linux内核启动过程分析
- Linux内核启动过程分析
- Linux内核启动过程分析
- linux内核启动过程分析
- Linux内核启动过程分析
- Linux内核启动过程分析
- linux内核启动过程分析
- Linux内核启动过程分析
- python 语法小记
- 关于'//<![cdata['和 '//]]>'解答
- PullToRefresh
- android edittext 边框 阴影 实现
- FPGA中IBUFDS、IBUFGDS、OBUFDS的运用
- linux内核启动过程分析
- 自定义vue全局组件use的使用
- Window 安装两个版本JDK,配置其中一个
- 控制服务器处理请求的数量(高并发)-防止用户重复点击导致多次请求
- android 使用Robotium自动化测试
- MySQL查询:查询一个表中类别字段中Max()最大值对应的记录
- java集合分析(7):ArrayList
- 随记
- 安卓开发中Banner添加头布局结合PullToRefresh实现上拉下拉