uboot启动linux分析,uboot启动zImage(go)和uImage(bootm)分析

1.之间差异。

bootm 加载linux镜像是加载uIamge,uIamge是由mkimage制作而来,和zIamge的差异是uIamge是zIamge压缩过的,bootm需要先对uIamge解压,解压地址为内核入口地址。当解压完成时uIamge和zIamge 几乎是相同的,具体差异可以论述。uboot目前只能支持uImage启动,不支持zImage启动

2.bootm解压过程

---------------------------------------------------------------------------

## Booting image at 08808000 ...

Image Name: Linux-2.6.14.7

Image Type: ARM Linux Kernel Image (uncompressed)

Data Size: 989172 Bytes = 966 kB

Load Address: 08008000

Entry Point: 08008000

Verifying Checksum ... OK

OK uboot bootm命令对uIamge的解压操作

---------------------------------------------------------------------------

Starting kernel ...

传递内核参数将控制权交给arch/arm/boot/compressed]head.S

----------------------------------------------------------------------------

如mx1ADS班子内存的起始地址为0x0800_0000,通过tftp 下载到0x0800_8000 +offset ,offset大于0x80_0000,即tftp 0x0880_8000 然后bootm 0x0880_8000 即

将0x0880_8000处的uIamge解压,解压地址即为mkimage 设置的kernel入口地址0x0800_8000。

2.bootm内核启动分析

通过分析uboot把控制权交给kernel的瞬间,我们可以知道bootm启动linux内核,它究竟做了哪些工作。

具体源码在uboot1.16 lib_arm/Armlinux.c do_bootm_linux(),大家有兴趣可以看下源码,这里不仔细分析了,网上资料超多。

void (*theKernel)(int zero, int arch, uint params) 通过对这个函数指针的操作实现控制权从uboot到linux的交接。

该函数可以等价于set pc=0x0800_8000 ,r0=0 ,r1=0xA0(mx1ads 芯片的id),r2=0x08000100(bootargs参数基址)。

我通过仿真器,设置了一个指令断点在0x0800_8000,可以看到该瞬间uboot做的操作。

>BKM>dr //查看当前时刻通用寄存器值

R00 = 00000000 R01 = 000000A0 R02 = 08000100 R03 = 08008000

R04 = 00000000 R05 = 08000124 R06 = 083DC0A9 R07 = 0841BC9C

R08 = 083DBFDC R09 = 083E0260 R10(SL) = 00000000 R11(FP) = 00000002

R12(IP) = 083DBFC0 R13(SP) = 083DBD44 R14(LR) = 08413984 PC = 08008000

CPSR = 600000D3 SPSR = B00000FF

>BKM>di 0x08008000 // 反汇编该地址区域代码

08008000: mov r0,r0

08008004: mov r0,r0

08008008: mov r0,r0

0800800c: mov r0,r0

08008010: mov r0,r0

08008014: mov r0,r0

08008018: mov r0,r0

0800801c: mov r0,r0

08008020: b 0x8008030

08008024: .long 0x16F2818

08008028: andeq r0,r0,r0

0800802c: streqd r1,[pc],-r4

08008030: mov r7,r1

08008034: mov r8,#0

08008038: mrs r2,cpsr

0800803c: tst r2,#3

08008040: bne 0x800804C

08008044: mov r0,#0x17

08008048: swi 0x123456

0800804c: mrs r2,cpsr

08008050: orr r2,r2,#0xC0

08008054: msr cpsr_c,r2

08008058: andeq r0,r0,r0

0800805c: andeq r0,r0,r0

08008060: add r0,pc,#0xC8

08008064: ldmia r0,{r1,r2,r3,r4,r5,r6,r12,r13}

08008068: sub r0,r0,r1

0800806c: beq 0x800809C

>BKM>dml 0x08000100 0x50 //uboot bootargs

08000100: 00000005 54410001 00000000 00000000 ....TA..........

08000110: 00000000 00000004 54410002 04000000 ........TA......

08000120: 08000000 0000000F 54410009 736E6F63 ........TA..snoc

08000130: 3D656C6F 53797474 2C30584D 32353131 =eloSytt,0XM2511

08000140: 386E3030 3D706920 746F6F62 6F722070 8n00=pi toobor p

08000150: 2F3D746F 2F766564 0073666E 00000000 /=to/ved.sfn....

08000160: 00000000 00000000 00000000 00000000 ................

通过仿真器可以很清晰的看到bootm先后完成了2部分工作。大家可以分析bootm源码

1.set bootargs 传递参数

2.set pc=0x0800_8000 ,r0=0 ,r1=0xA0

3.对比zImage 分析

通过tftp 0x0800_8000 命令直接将zImage下载到0x0800_8000地址

此时对0x08008000 反汇编可以得到和arch/arm/boot/compressed/head.S一致的汇编代码,说明这是kernel的入口

08008000: msr cpsr_c,#0xD3

08008004: bl 0x8008150

08008008: mov r10,r5

0800800c: beq 0x8008148

08008010: bl 0x80081B0

08008014: mov r8,r5

08008018: beq 0x8008148

0800801c: bl 0x80080D8

08008020: ldr r13,[pc,#+4]

08008024: add r14,pc,#0x68

08008028: add pc,r10,#0xC

0800802c: andgt r8,r0,r0,asr r0

08008030: andgt r2,r11,r0

08008034: andgt r2,r11,r0

08008038: andgt r2,r12,r0,lsl #1

0800803c: ldrgth r14,[r13],-r12

08008040: andgt r5,r12,r12,asr #1

08008044: mulgts r12,r12,r0

08008048: andgt r5,r11,r12,asr #0x13

0800804c: ldrgtsh r3,[r11],-r8

08008050: sub r3,pc,#0x28

08008054: ldmia r3!,{r4,r5,r6,r7}

08008058: cmp r4,r5

0800805c: cmpne r5,r6

08008060: ldrne r11,[r4],#+4

08008064: strne r11,[r5],#+4

08008068: bne 0x800805C

0800806c: mov r11,#0

08008070: cmp r6,r7

08008074: strcc r11,[r6],#+4

08008078: bcc 0x8008070

0800807c: ldmia r3,{r4,r5,r6,r13}

08008080: str r9,[r4,#+0]

此时用go命令 go 0x08008000,go命令本质就是改变当前pc值,即pc=go 0x08008000

断点位置为 0x08008000 ,使用go 会在 0x08008000处停下来

>BKM>dr //此时通用寄存器值为

R00 = 00000000 R01 = 083E0264 R02 = 000F0000 R03 = 0000000C

R04 = 08008000 R05 = 08808000 R06 = 41129200 R07 = 083E0264

R08 = 08000000 R09 = 18000000 R10(SL) = 00000000 R11(FP) = 00000020

R12(IP) = 08808354 R13(SP) = 088E9464 R14(LR) = 08808298 PC = 08008000

CPSR = 400000D3 SPSR = B00000FF

//uboot bootargs

08000100: 00000000 00000000 00000000 00000000 ................

08000110: 00000000 00000000 00000000 00000000 ................

08000120: 00000000 00000000 00000000 00000000 ................

08000130: 00000000 00000000 00000000 00000000 ................

08000140: 00000000 00000000 00000000 00000000 ................

08000150: 00000000 00000000 00000000 00000000 ................

08000160: 00000000 00000000 00000000 00000000 ................

08000170: 00000000 00000000 00000000 00000000 ................

08000180: 00000000 00000000 00000000 00000000 ................

08000190: 00000000 00000000 00000000 00000000 ................

080001A0: 00000000 00000000 00000000 00000000 ................

这个时候发现kernel无法正确启动zImage

4,通过仿真器对go命令加以改造

a.将通用寄存器值改成

R00 = 00000000 R01 = 000000A0 R02 = 08000100 R03 = 0000000C

R04 = 08008000 R05 = 08808000 R06 = 41129200 R07 = 083E0264

R08 = 08000000 R09 = 18000000 R10(SL) = 00000000 R11(FP) = 00000020

R12(IP) = 08808354 R13(SP) = 088E9464 R14(LR) = 08808298 PC = 08008000

CPSR = 400000D3 SPSR = B00000FF

b.通过仿真器修改 0x08000100 地址的值

sml 0x08000100 00000005 54410001 00000000 00000000 00000000 00000004 54410002 04000000 08000000 0000000F 54410009 736E6F63

sml 0x08000130 3D656C6F 53797474 2C30584D 32353131 386E3030 3D706920 746F6F62 6F722070 2F3D746F 2F766564 0073666E 00000000

>BKM>dml 0x08000100 0x50

08000100: 00000005 54410001 00000000 00000000 ....TA..........

08000110: 00000000 00000004 54410002 04000000 ........TA......

08000120: 08000000 0000000F 54410009 736E6F63 ........TA..snoc

08000130: 3D656C6F 53797474 2C30584D 32353131 =eloSytt,0XM2511

08000140: 386E3030 3D706920 746F6F62 6F722070 8n00=pi toobor p

08000150: 2F3D746F 2F766564 0073666E 00000000 /=to/ved.sfn....

08000160: 00000000 00000000 00000000 00000000 ................

然后让程序执行,这样通过uboot也可以让zImage得以执行。

可见go和bootm差异就是 go只是改写pc值,而bootm传递r0,r1,r2还有bootargs

有疑问加站长微信联系(非本文作者)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Uboot启动Linux过程详解: 1. Uboot加载内核镜像:Uboot首先会从存储设备(如SD卡、NAND Flash等)中加载内核镜像到内存中。 2. 设置内核启动参数:Uboot会设置内核启动参数,包括内核镜像在内存中的位置、根文件系统的位置、启动参数等。 3. 启动内核:Uboot会将控制权交给内核,让内核开始执行。内核会进行一系列初始化操作,包括初始化CPU、内存、设备驱动等。 4. 挂载根文件系统:内核会挂载根文件系统,使得用户可以访问文件系统中的文件和目录。 5. 启动用户空间:内核会启动用户空间,即启动init进程。init进程会读取配置文件,启动各种系统服务和应用程序。 6. 用户空间运行:一旦用户空间启动成功,系统就进入了正常的运行状态,用户可以使用各种应用程序和系统服务。 总之,Uboot启动Linux的过程是一个复杂的过程,需要多个组件协同工作,才能让系统正常启动并运行。 ### 回答2: Uboot是嵌入式系统中常用的一个开源启动加载程序,其主要功能是在嵌入式操作系统中启动Linux系统,并初始化系统硬件资源。Uboot在整个Linux系统启动过程中起到很关键的作用,下面就来详细介绍一下Uboot启动Linux过程. 一、Uboot的加载 第一个引导程序(Bootloader)需要存放在系统的闪存中,是Linux系统启动的重要组成部分。当开机后CPU默认开始执行闪存芯片0的地址,此时Uboot就被加载到RAM中,并执行。由于Uboot同样位于一块桥接器和一个NOR Flash的四接口ARM微控制器总线上,因此Uboot在存储器刚刚发挥了重要作用。 在Uboot启动过程中,系统会根据用户的选择进行环境的设置,比如启动选项、串口设置等。同时,Uboot还会初始化内存,并将内核镜像加载到内存中,准备启动内核。 二、内核的启动 Linux内核启动主要分为五个过程,分别是: 1.内核加载 当Uboot初始化完成后,系统进入内核加载阶段。Uboot会将存放在NOR Flash中的内核镜像加载到系统主内存中。在加载内核时,会有一个fdt文件,该文件是系统在启动时加载设备树的重要文件,在设备树的启动阶段,大部分设备驱动程序都是通过fdt中的节点进行解析。 2.内核装载初始化 在内核镜像成功加载到内存中后,Linux内核开始进入装载初始化,该阶段主要进行一些内部的初始化工作,比如初始化调度程序、内存管理、文件系统等;此外还会启动ELF文件解析程序,解析各个驱动模块,以便后续的设备树解析和驱动程序的加载。 3.设备树解析 在内核镜像加载到内存中之后,Linux会对设备树进行解析。设备树是在启动时由Uboot加载、传递给内核的一种数据结构,主要用于描述系统的硬件资源分布情况,是操作系统启动过程中很关键的一环,因为设备树可以为操作系统提供有关系统硬件的信息,便于操作系统启动后初始化对应的硬件资源。 4.初始化进程 在设备树解析完成之后,Linux会进入初始化进程的阶段。在这个过程中,系统会完成一系列的启动脚本,完成基本系统的初始化,并启动基本服务。 5.用户空间启动 当初始化进程执行完毕后,系统进入用户空间启动阶段。此时可以执行用户的应用程序,系统也正式进入了可用状态了。 三、总结 以上就是Uboot启动Linux过程的详解了。在整个启动过程中,Uboot不仅完成了硬件资源初始化,还实现了内核和用户空间的启动,是整个系统的重要组成部分。对于嵌入式设备的开发者来说,深入了解Uboot启动过程,对于准确定位问题和有序开发代码具有很大的帮助。 ### 回答3: uboot是嵌入式系统中常用的一个启动引导程序,其作用是加载Linux内核文件到系统中,并启动该内核从而让系统正常运行。本文就uboot启动linux的过程进行详细的分析。 uboot启动linux的过程: 1. CPU从复位向量开始执行: 当CPU启动时,会首先寻找复位向量所在的地址,并执行该地址中存储的指令。在嵌入式系统中,这个复位向量通常被配置为uboot程序的起始地址。 2. 加载uboot程序: uboot启动后会先加载自身的程序代码。uboot的程序包括bootloader和一些工具函数,它们可以执行一些用户定制的任务,比如读写参数、显示系统信息等操作,然后才会加载Linux内核。 3. 加载Linux内核: 在uboot加载内核时,它首先要根据指定的地址和大小,从存储介质中读取内核文件,并将其存储到内存中。在读取内核文件期间,uboot会进行一些配置操作,比如初始化内存、配置内存映射等操作。 4. 启动Linux内核: Linux内核启动时需要设置一些参数,这些参数通常由uboot传递给内核。例如,uboot会告诉内核内存的位置和大小、设备树等信息。接着,内核会根据这些参数进一步初始化系统,比如建立内存映射表、配置硬件设备等操作。这些操作完成后,Linux内核会开始执行用户空间程序,使得系统正常运行。 总结: 通过上述分析可知,uboot启动Linux的过程涉及到多个环节,其中包括uboot程序的加载、Linux内核的加载以及启动Linux内核时传递参数等操作。在实际系统中,这些过程需要针对具体的硬件平台进行适当的定制,才能保证系统正常启动和运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值