arm linux 启动流程之 进入内核

发布者:SereneNature7最新更新时间:2016-06-16 来源: eefocus关键字:arm  linux  启动流程  内核 手机看文章 扫描二维码
随时随地手机看文章
还是从编译链接生成vmlinux的过程来看吧,由一大堆.o文件链接而成,第一个就是

kernel/arch/arm/kernel/head-armv.o ,而且我们还看到了
lds链接文件kernel/arch/arm/vmlinux.lds,先把它分析一下
ENTRY(stext) //入口点是stext 应该就在head-armv.s中了
SECTIONS
{
 . = 0xC0008000;  //基址,是内核开始的虚拟地址
 .init : {   /* Init code and data  */
  _stext = .;
  __init_begin = .;
   *(.text.init)
  __proc_info_begin = .;
   *(.proc.info)
  __proc_info_end = .;
  __arch_info_begin = .;
   *(.arch.info)
  __arch_info_end = .;
  __tagtable_begin = .;
   *(.taglist)
  __tagtable_end = .;
   *(.data.init)
  . = ALIGN(16);
  __setup_start = .;
   *(.setup.init)
  __setup_end = .;
  __initcall_start = .;
   *(.initcall.init)
  __initcall_end = .;
  . = ALIGN(4096);
  __init_end = .;
 }
关于虚拟地址和物理地址的:使用MMU后,系统就会使用虚拟地址,通过MMU来指向
实际物理地址而在这里我们的0xC0008000实际物理地址就是0x30008000,
具体关于MMU的介绍参考《ARM体系结构与编程》。
到head-armv.s找到程序的入口
  .section ".text.init",#alloc,#execinstr
  .type stext, #function
ENTRY(stext)
  mov r12, r0
  mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
  msr cpsr_c, r0   @ and all irqs disabled
  bl __lookup_processor_type
  teq r10, #0    @ invalid processor?
  moveq r0, #'p'   @ yes, error 'p'
  beq __error
  bl __lookup_architecture_type
  teq r7, #0    @ invalid architecture?
  moveq r0, #'a'   @ yes, error 'a'
  beq __error
  bl __create_page_tables
  adr lr, __ret   @ return address
  add pc, r10, #12   @ initialise processor
来看看上一句跳到哪里去了
去追寻r10的值,是在__lookup_processor_type子函数中赋的
__lookup_processor_type:
  adr r5, 2f   //r5 标号2的地址 基址是0x30008000
  ldmia r5, {r7, r9, r10} //r7=__proc_info_end  r9=__proc_info_begin
  sub r5, r5, r10  //r10 标号2的链接地址   基址是0xc0008000
  add r7, r7, r5   @ to our address space
  add r10, r9, r5  //r10 变换为基址是0x30008000的__proc_info_begin
2:  .long __proc_info_end
  .long __proc_info_begin
  .long 2b
这样r10中存放的是__proc_info_begin的地址,因为现在我们还没有打开MMU
所以还是需要把基址变换到0x30008000,接着我们就去找__proc_info_begin吧
注意到在上面的vmlinux.lds中有这个标号,下来链接的是.proc.info段,
在kernel/arch/arm/mm/proc-arm920.s的最后找到了这个段
 .section ".proc.info", #alloc, #execinstr

 .type __arm920_proc_info,#object
__arm920_proc_info:
 .long 0x41009200
 .long 0xff00fff0
 .long 0x00000c1e   @ mmuflags
 b __arm920_setup
ok,这样我们就知道add pc, r10, #12跳到哪里去了,因为这个地址刚好放了条跳转语句
注意了b语句用的都是相对地址,所以不需要变换地址,反正是跳到__arm920_setup,而且
上一条语句是adr lr, __ret,设定了__arm920_setup的返回地址是__ret,所以执行完
__arm920_setup后回到head-armv.s的__ret标号继续执行.
__ret:  ldr lr, __switch_data
  mcr p15, 0, r0, c1, c0 //注意这里了,在这里打开了MMU
  mov r0, r0
  mov r0, r0
  mov r0, r0
  mov pc, lr //跳到__mmap_switched,这里已经用了虚拟地址了吧
 // 这条指令ldr lr, __switch_data加载的__mmap_switched地址就是虚拟地址啊
__switch_data: .long __mmap_switched
从__mmap_switched一路执行下来,就要调到C语言代码中去了
  b SYMBOL_NAME(start_kernel) //在kernel/init/main.c中
这个程序不是特别复杂,细心看看还是能大概看懂,我也不能去一一注释
这里有一个流程图

arm linux 启动流程之 进入内核

到了C语言中就不是很难理解了
 lock_kernel();
 printk(linux_banner);
 setup_arch(&command_line);
 printk("Kernel command line: %s/n", saved_command_line);
 parse_options(command_line);
 trap_init();
 init_IRQ();
 sched_init();
 softirq_init();
 time_init();
就是一大堆初始化工作,追着每个函数去看好了

start_kernel最后调用的一个函数
static void rest_init(void)
{
 kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
 unlock_kernel();
 current->need_resched = 1;
  cpu_idle();

用kernel_thread建立了一个init进程,执行的是main.c中的init函数
 lock_kernel();
 do_basic_setup();
在do_basic_setup中调用了do_initcalls函数
各种驱动都是在do_initcalls(void)中完成的
static void __init do_initcalls(void)
{
 initcall_t *call;

 call = &__initcall_start;
 do {
  (*call)();
  call++;
 } while (call < &__initcall_end);

 flush_scheduled_tasks();
}
__initcall_start也是在vmlinux.lds中赋值的,那就需要找到.initcall.ini这个段
在kernel/include/linux/init.h中可以找到
#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
typedef int (*initcall_t)(void);
#define __initcall(fn)        /
 static initcall_t __initcall_##fn __init_call = fn
仔细研究下就发现这是把初始化函数的地址放到了.initcall.init段中
这样就可以不断调用驱动的初始化函数了
如果没有定义MODULE,那么#define module_init(x) __initcall(x);
所以如果要把驱动的编译进内核就很简单了吧
init的最后
 if (execute_command)
  execve(execute_command,argv_init,envp_init);
execute_command与ppcboot传的命令行参数是有关的哦,就是init=/linuxrc
这样就要去执行根目录下的linuxrc脚本,这个脚本会去执行busybox
而busybox又去执行/etc/init.d/rcS脚本,这个脚本又去执行/usr/etc/rc.local
完了

关键字:arm  linux  启动流程  内核 引用地址:arm linux 启动流程之 进入内核

上一篇:arm linux 启动流程
下一篇:ARM Linux启动过程学习

推荐阅读最新更新时间:2024-03-16 14:57

第1天-ARM工作模式
第1天-ARM工作模式 1、ARM体系CPU工作状态:ARM状态和Thumb状态 ARM状态:处理器执行32位的字对齐的ARM指令; Thumb状态:处理器执行16位的、半字对齐的Thumb指令; 在程序运行的过程中,可以在两种状态之间进行相应的转换。处理器工作状态的转变并不影响处理器的工作模式和相应寄存器中的内容。CPU上电处于ARM状态 2、存储器格式: Arm体系结构将存储器看做是从零地址开始的字节的线性组合。从零字节到三字节放置第一个存储的字(32位)数据,从第四个字节到第七个字节放置第二个存储的字数据,一次排列。作为32位的微处理器,arm体系结构所支持的最大寻址空间为4GB。 大端格式和小端格式
[单片机]
基于ARM嵌入式系统的PC/104总线设计
当前已经进入嵌入式系统全面应用时代,基于ARM处理器和嵌入式Linux的嵌入式系统以其设计灵活、软硬件可裁剪、性能优越、成本低等特点和优势,倍受设计者和使用者青睐。 其在低功耗、低成本应用领域确立了其市场领导地位;同时随着x86架构的不断成熟和x86处理器的应用范围越来越广,人们逐步开始认识到其本身架构的限制,在工业控制领域嵌入式ARM处理器将有望取代传统的X86处理器。    PCI04总线是一种近年来在国际上广泛流行的专门为嵌入式系统而定义的工业控制总线,被IEEE协会定义为IEEE-P996,该系列产品已广泛应用于通信设备、车辆导航、工程控制等各种领域。由于PC或PC/AT的主板和扩展卡的尺寸及功耗标准都太大
[单片机]
基于<font color='red'>ARM</font>嵌入式系统的PC/104总线设计
嵌入式Linux操作系统的驱动程序开发要点
在Linux操作系统下有3类主要的设备文件类型:块设备、字符设备和网络设备。这种分类方法可以将控制输入/输出设备的驱动程序与其他操作系统软件分离开来。 字符设备与块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般紧接着发生。块设备则不然,它利用一块系统内存作为缓冲区,若用户进程对设备的请求能满足用户的要求,就返回请求的数据;否则,就调用请求函数来进行实际的I/O操作。块设备主要是针对磁盘等慢速设备设计的,以免耗费过多的CPU时间用来等待。网络设备可以通过BSD套接口访问数据。 每个设备文件都有其文件属性(c/b),表示是字符设备还是块设备。另外每个文件都有2个设备号,第一个是主设备号,标识驱动程序;第二个是
[嵌入式]
ubuntu 9.04 环境下实现ylp2410 Linux2.6.8内核编译
今天终于在ubuntu上完成了内核编译,现将过程记录如下。 首先,先装qt一些相关的软件包,若后面提示有错误,很可能是缺少一些软件包, 再使用sudo apt-get install **命令即可下载安装。。。。 1.sudo -i 进入root 2.把交叉编译工具复制到/work/tools/下,并解压arm-linux-gcc-3. 4 . 1.tar .bz2, 步骤省略,如下图所示。 2.把交叉编译器路径添加到系统的路径中: 在 bashrc的最后一行加上如下一行: PATH=$PATH:/work/tools/usr/local/arm/3.4.1/bin 截图如下: 启动新系统路径: #source /ro
[单片机]
ubuntu 9.04 环境下实现ylp2410 <font color='red'>Linux</font>2.6.8<font color='red'>内核</font>编译
嵌入式Linux系统的设计与应用
摘要:随着嵌入式Linux系统的迅速发展,嵌入式Linux已发展成为嵌入式操作系统的一个重要分支。本文介绍了嵌入式Linux的设计和几种流行的嵌入式Linux系统。 关键词:嵌入式Linux 一、引言 嵌入式系统(Embedded Systems)是根据应用的要求,将操作系统和功能软件集成于计算机硬件系统之中,从而实现软件与硬件一体化的计算机系统。嵌入式系统出现于60年代晚期,它最初被用于控制机电电话交换机,如今已被广泛的应用于工业制造、过程控制、通讯、仪器、仪表、汽车、船舶、航空、航天、军事装备、消费类产品等众多领域。嵌入式系统在数量上远远超过了各种通用计算机系统:计算机系统核心CPU,每年在全球范围内的产量大概在二十亿
[嵌入式]
专注ARM,恩智浦2009年的中国“芯”路
  自2月获得Cortex-M0授权后,仅仅几周时间,恩智浦便推出了业界首款基于该内核的功能性硅芯片,“这对ARM也是创纪录的,”恩智浦半导体副总裁兼微控制器产品线总经理Geoff Lees在近日的媒体见面会上自豪地说,而此前的内核,往往需要2年的时间。 恩智浦半导体副总裁兼微控制器产品线总经理Geoff Lees   在诸多采用ARM Cortex-M3处理器为核心的MCU供应商中,恩智浦可谓是姗姗来迟,早前Luminary(被TI收购)、ST 都已经推出基于此系列的MCU,且表现不俗。正当广大工程师纷纷猜测恩智浦M3内核产品何时诞生时,不仅Cortex-M3来了,随之而来的,还
[单片机]
GNU ARM汇编--(十九)u-boot-nand-spl启动过程分析
在理解bootloader后,花些时间重新学习了开源软件的makefile和相关脚本之后,自己的u-boot移植工作也比较顺利的完成了: 移植环境: ubuntu 12.04 U-Boot 2012.07 (Nov 28 2012 - 20:05:48) arm-none-linux-gnueabi-gcc (Sourcery G++ Lite 2009q1-203) 4.3.3 GNU ld (Sourcery G++ Lite 2009q1-203) 2.19.51.20090205 我移植的uboot只支持nand flash,原因是手头没办法烧写nor flash
[单片机]
紫光同芯基于R52+内核的车规MCU获功能安全最高认证
汽车“新四化”的深入发展,对汽车芯片的性能表现提出更高要求。紫光新一代THA6系列MCU,最多配备6颗ARM Cortex-R52+内核(含锁步),主频最高达400MHz,内置大容量的嵌入式非易失存储器,拥有出色的实时性和多核性能表现,能够满足传统燃油车和新能源汽车在动力(引擎控制、电驱控制、电池管理等)、底盘(转向、制动等)、车身、智驾等需要高安全特性的应用需求,同时可支持域控制器、区域控制器等新的应用场景,为新的汽车电子电气架构提供良好的软硬件基础。 近日,紫光新一代THA6系列MCU通过国际权威认证机构SGS关于功能安全开发流程体系以及功能安全产品设计的评估,获得符合IS0 26262标准的ASIL D等级功能安全
[汽车电子]
紫光同芯基于R52+<font color='red'>内核</font>的车规MCU获功能安全最高认证
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved