uboot和系统移植-第1部分-2.1 uboot学习前传

2024-03-18 06:32

本文主要是介绍uboot和系统移植-第1部分-2.1 uboot学习前传,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

uboot和系统移植-第1部分-2.1 uboot学习前传
第一部分、章节目录
2.1.1. 为什么要有uboot
(1)uboot最主要作用是用来启动操作系统内核。因为操作系统内核本身不能自己启动自己。
就像闹钟这东西是用来叫人起床的,人不能自己叫醒自己。
(2)uboot除了启动操作系统,还有别的一些辅助功能
2.2.1.1 计算机系统的主要部件
(1)计算机系统就是有CPU来做核心进行运行的系统。典型的计算机系统有:PC机(台式机+笔记本)、
嵌入式设备(手机、平板电脑、游戏机)、单片机(家用电器像电饭锅、空调)
(2)计算机系统运行时需要的主要核心部件是3个东西:CPU+外部存储器(Flash/硬盘)+内部存储器(DDR
 SDRAM/SDRAM/SRAM)
 2.2.1.2、 PC机启动过程
 (1)典型的PC机的部署:BIOS程序部署在PC机主板上(随主板出厂时已经预制了),能够装系统就是通过BIOS的。
 操作系统部署在硬盘上,内存在掉电时无作用,CPU在掉电时不工作;
 (2)启动过程:PC上电后先执行BIOS程序(实际上PC的BIOS就是NorFlash),BIOS程序负责初始化DDR内存,负责
 初始化硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中执行OS直到启动(OS启动后BIOS就无用了)
 2.2.1.3 典型嵌入式Linux系统启动过程
(1)嵌入式系统的部署和启动都是参考PC机的,只是设备上有一些差别。
(2)典型嵌入式系统的部署:uboot程序部署在Flash(能作为启动设备的Flash)上,OS部署在Flash
(嵌入式系统中用Flash代替了硬盘)上、内存在掉电时无作用,CPU在掉电时不工作;
(3)启动过程:嵌入式系统上电后先执行uboot、然后uboot负责初始化DDR,初始化Flash,然后将OS从
Flash中读取到DDR中,然后启动OS(OS启动后uboot就无用了)

总结:嵌入式系统和PC机的启动过程几乎没有两样,只是BIOS成了uboot,硬盘成Flash。

2.2.1.1 android系统启动过程
(1)android系统的启动和linux系统(前面讲的典型的嵌入式系统启动)几乎一样。几乎一样意思
就是前面完全一样,只是在内核启动后加载根文件系统后不同了。
(2)可以认为启动分为2个阶段:第一个阶段是uboot到OS启动;第二个阶段是OS启动后到rootfs加载到
命令行执行;现在我们研究的是第一个阶段。android的启动和Linux的差别在第二阶段。

2.2.1.5 总结:uboot到底是干嘛的
(1)uboot主要作用是用来启动操作系统内核。
(2)uboot还要负责部署整个计算机系统。
(3)uboot中还有操作Flash等板上硬件的驱动。
(4)uboot还得提供一个命令行界面供人来操作

2.1.2 为什么是uboot
2.1.2.1 uboot是从哪里来的
(1)uboot是SourceForge上的开源项目
(2)uboot项目的作者:一个德国人最早发起的项目
(3)uboot就是由一个人发起,然后由整个网络上所有感兴趣的人


2.1.2.2 uboot的发展历程
(1)自己使用的小开源项目
(2)被更多人认可使用
(3)被SoC厂商默认支持.
总结:uboot经过多年发展,已经成为事实上的业内bootloader标准。现在大部分
的嵌入式设备都会默认使用uboot来作为bootloader。
2.1.2.3 uboot的版本号问题
(1)早期的uboot的版本号类似于这样:uboot1.3.4.后来版本号变成了类似于uboot-2010.06
(2)uboot的核心部分几乎没怎么变化,越新的版本支持的开发板越多而已,对应一个老版本的芯片来说
新旧版本的uboot并没有差异。
2.1.2.4 uboot的可移植性的正确理解
(1)uboot就是universal bootloader(通用的启动代码),通用的意思就是在各种地方都可以用。
(2)uboot具有可移植性并不是说uboot在哪个开发板都可以随便用,而是说uboot具有在源代码
级别的移植能力,可以针对都个开发板进行移植,移植后就可以在这个开发板上使用了。

2.1.2.5 总结:时势造英雄,任何牛逼的东西都是时代的产物
uboot的出现是一种必然,如果没有uboot也会有另一个bootloader来代替。

2.1.3 uboot必须解决哪些问题
2.1.3.1 自身可开机直接启动
(1)一般的SoC都支持多种启动方式,譬如SD卡启动、NorFlash启动、NandFlash启动等......
uboot要能够开机启动,必须根据具体的SoC的启动设计来设计uboot
(2)uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证从相应的启动介质启动。
uboot中第一阶段的start.S文件中具体处理了这一块。
与裸机里面非常像,因为uboot本来就是一个裸机程序。
2.1.3.2 能够引导操作系统内核启动并给内核传参
(1)uboot的终极目标就是启动内核。
(2)linux内核在设计的时候,设计为可以被传参。也就是说我们可以在uboot中事先给linux内核
准备一些启动参数放在内存中特定位置然后传给内核,内核启动后会到这个特定位置去取uboot传
给他的参数,然后在内核中解析这些参数,这些参数将被用来指导linux内核的启动过程。
传参不同控制内核启动方式不同。内核编译好之后就不用动了,内核要改什么东西,去改它的配置
文件就可以了。好处是不用重新编译内核程序了。
就相当于uboot的环境变量就是用来动态的控制uboot的执行的。

2.1.2.3 能够提供系统部署功能
(1)uboot必须能够被人借助而完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上
的烧录下载工作。
(2)裸机教程中刷机就是利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动。
uboot本身就能完成刷机工作。


2.1.2.4 能进行soc级和板级硬件管理
(1)uboot中实现了一部分硬件的控制能力(uboot中初始化了一部分硬件),因为uboot为了完成
一些任务必须让这些硬件工作。譬如uboot要实现刷机必须能驱动iNand,譬如uboot要在刷机时LCD
上显示进度条就必须能驱动LCD,譬如uboot能够通过串口提供操作界面就必须驱动串口。
所以说uboot有很多的硬件驱动在里面。
譬如说uboot要实现网络功能就必须驱动网卡芯片。
(2)SoC级(譬如串口)就是SOC内部外设,板级就是SoC外面开发板的硬件(譬如网卡、iNand)
2.1.2.5 uboot的“生命周期”
(1)uboot的生命周期就是指:uboot什么时候开始运行,什么时候结束运行。
(2)uboot本质上是一个裸机程序(不是操作系统)。意味是uboot是单线程的,从uboot这边可以ping
主机,但是主机是ping不通uboot的。因为uboot这里支持一个ping命令,你执行ping命令的时候它
会向我们的主机去发一下ping命令包,主机如果回了这些数据包,它收到了这些数据包就表示ping
通了,但是从主机这边去ping Uboot是不行的,因为你主机给它发了包,uboot根本就不理你,
uboot程序就没有去那里去收包,根本就不知道你给他发了包。它还在自己的死循环里沉醉呢。
但是在操作系统里面就不一样了,可以双向ping通,因为操作系统是平行的。

注意:裸机程序有个特点,一旦结束就不能再执行了。一旦uboot开始SoC就会单纯运行uboot(意思
就是uboot运行的时候别的程序是不可能同时运行的,对CPU是独占的),一旦uboot结束运行则
无法再回到uboot(所以uboot启动了内核后uboot自己本身就死了,要想再次看到uboot界面
只能重启系统。重启并不是复活了刚才的uboot,重启只是uboot的另一生,跟刚才的生命没有任何关系了
)。

(3)uboot的入口和出口。
uboot的入口就是开机自动启动,uboot的唯一出口就是启动内核。一启动内核就死了。
不启动内核还能回来。不管你启动内核是否成功,uboot必死。
uboot还可以执行很多别的任务(譬如烧录系统),但是其他任务执行完后都可以回到uboot的
命名行继续执行uboot命令,而启动内核命名一旦执行就回不来了。

2.1.3.6 总结:一切都是为了启动内核

2.1.4 uboot的工作方式
2.1.4.1 从裸机程序镜像uboot.bin说起
(1)uboot的本质就是一个裸机程序,和我们裸机全集中写的那些裸机程序xx.bin并没有本质区别。
如果非要说有区别,那就是:我们写的大部分小于16KB,而uboot大于16KB(一般uboot在180k-400
k之间)
(2)uboot本身是一个开源项目,由若干个.c文件和.h文件组成,配置编译之后会生成一个uboot.
bin,这就是uboot这个裸机程序的镜像文件。然后这个镜像文件被合理的烧录到启动介质中拿给S
oC去启动。
(3)uboot运行时会被加载到内存中然后一条指令一条指令的拿给CPU去运行。
2.1.4.2 uboot的命令式shell界面
(1)普通的裸机程序运行起来就直接执行了,执行时效果和代码有关。
(2)有些程序需要和人进行交互,于是乎程序中就实现了一个shell(shell就是提供人机交互的一个
界面)

注意:shell并不是操作系统,和操作系统一点关系都没有。linux中打开一个终端后就得到一个
shell,可以输入命令回车执行。uboot中的shell工作方式和linux中的终端shell非常像(其实
几乎一样的,只是命令集不一样。譬如linux中可以ls,uboot中ls就不识别)

shell并不是操作系统的专利,并不是操作系统才有shell,裸机也可以写一个shell

2.1.4.3 掌握uboot使用的2个关键点:命令和环境变量
(1)uboot启动后大部分时间和工作都是在shell下完成的(譬如uboot要部署系统要在shell下
输入命令、要设置环境变量也得在命令行下,要启动内核也要在命令行下敲命令)
(2)命令就是uboot的shell中可以识别的各种命令。uboot中有几十个命令,其中有一些常用
另一些不常用(我们还可以自己给uboot添加命令)。
(3)uboot的环境变量和操作系统的环境变量工作原理和方式完全相同。
uboot在设计时借助了操作系统的设计理念(命令行工作方式借鉴了Linux终端命令行,环境变量
借鉴了操作系统环境变量,uboot的驱动管理几乎完全照抄了Linux的驱动框架)
(4)环境变量可以被认为是系统的全局变量,环境变量名都是系统内置的(认识就认识,不认识就
不认识,这部分是系统自带的默认的环境变量,譬如PATH:但是也有一部分环境变量是自己添加的
自己添加的系统就不认识但是我们自己认识)
系统或者我们自己的程序在运行时可以通过读取环境变量来指导程序的运行。这样设计的好处就是、
灵活,譬如我们要让一个程序更改运行方法,不用去重新修改程序代码再重新编译运行,而只要
修改相应的环境变量就可以了。
(5)环境变量就是运行时的配置属性

通过命令printenv打印所有的环境变量
hisilicon # printenv //printenv意思是打印当前系统的环境变量
bootdelay=1
baudrate=115200
ethaddr=00:00:23:34:45:66
ipaddr=192.168.1.10
netmask=255.255.255.0
bootfile="uImage"
serverip=192.168.1.100
bootcmd=sf probe 0;sf read 0x82000000 0x100000 0x300000;bootm 0x82000000
bootargs=mem=32M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1024K(boot),3072K(kernel),12288K(rootfs)
stdin=serial
stdout=serial
stderr=serial
verify=n
ver=U-Boot 2010.06 (Nov 19 2018 - 19:03:32)

Environment size: 438/262140 bytes


例如修改几秒内按回车进入uboot的环境变量bootdelay
hisilicon # setenv bootdelay 10     //把bootdelay修改为10秒
hisilicon # saveenv                 //修改完保存一下
Saving Environment to SPI Flash...
Erasing SPI flash, offset 0x00080000 size 256K ...done
Writing to SPI flash, offset 0x00080000 size 256K ...done

2.1.5 uboot的常用命令1
2.1.5.1 类似Linux终端的行缓冲命令行
格式  命令  参数1   参数2 ...
      xxx   yyy     zzz   ... //中间有空格
(1)行缓冲的意思就是:当我们向终端命令行输入命令的时候,这些命令没有立即被系统
识别,而是被缓冲到一个缓冲区(也就是系统认为我们还没有输入完),当我们按下回车键
后系统就认为我们输入完了,然后将缓冲区中所有刚才输入的作为命令拿去分析处理。
(2)Linux终端设计有3中缓冲机制:无缓冲(敲一个字母处理一个)、行缓冲、全缓冲(缓冲区满了才会处理)

2.1.5.2 有些命令有简化的别名
(1)譬如printenv命令可以简化为print,可以按Tab自动补全
查询命令help printenv
2.1.5.3 有些命令会带参数(注意格式是固定的)。有些命令就是不带参数的
譬如printenv/print命令;有些命令带可选的参数(可以带也可以不带,当然带不带参数的执行结果
是不同的);有些命令带必须的参数(譬如setenv/set 命令)
例如:help不带任何参数表示打印出系统所有的命令
      如果help后面单独跟某一个命令,它就会把某一个命令的解释单独打印给你

2.1.5.4 命令中特殊符号(譬如单引号)
(1)uboot的有些命令带的参数非常长,为了告诉uboot这个非常长而且中间有好多空格的东西是
他的一整个参数,所以用单引号将这个很长且中间有空格隔开的参数引起来。
例如:set bootcmd ‘movi read kernel 20008000; bootm 20008000’  //里面的分号表示前后
是两个独立的命令。前后的单引号把它们引起来当做一个整体参数
为什么要把它们用单引号引起来呢?是因为他们之间有分号

例如setenv bootargs root=/dev/nfs
nfsroot=192.168.1.141:/root/s3c2440/build_rootfs/aston_rootfs
这个就没必要加单引号,因为这个参数内部没有分号,有空格没有关系

(2)别的符号也许也有,而且有特定的意义。当碰到uboot的命令行有特殊符号时要注意不是弄错了,
而是可能有特别的含义。

2.1.5.5 有些命令是一个命令族(譬如movi)
(1)命令族意思就是好多个命令开头都是用同一个命令关键字的,但是后面的参数不一样,这些
命令的功能和作用也不同。这就叫一个命令族。
(2)同一个命令族中所有的命令都有极大的关联,譬如movi开头的命令都和moviNand(EMMC、
iNand)操作有关。
uboot官方不管这些命令,芯片厂商可以自己添加命令的

2.1.5.5 第一个命令:printenv/print
(1)print命令不用带参数,作用是打印出系统中所有的环境变量。
(2)环境变量就好像程序的全局变量一样,程序中任何地方都可以根据需要去调用或者更改环境变量
(一般都是调用)。
环境变量和全局变量不同之处在于:全局变量的生命周期是在程序的一次运行当中,开始运行时诞生
程序结束时死亡,下次运行程序时从头开始;
但是环境变量被存储在Flash的另一块专门区域(Flash上有一个环境变量分区),一旦我们在程序中
保存了该环境变量,那么下次开机时该环境变量的值将维持上一次更改 保存后的值。

2.1.6 uboot的常用命令2
(1)用法:set name value
2.1.6.1 设置(添加/更改)环境变量:setenv/set

set bootdelay 3  //如果你不保存改的只是内存里面的环境变量,关机重启又回去了
         环境变量在Flash中是有对应分区的,Flash中从低到高对应的分区为:
         uboot->var(环境变量)->OS ->rootfs         
器件启动的时候,uboot及var(环境变量)会被弄到内存DDR中来,在内存中也会维护一份
环境变量,内存中的这份环境变量从哪里来的呢?开机的时候从Flash中读取来的,只读一次。
就是uboot开机的时候的那一次。uboot工作的时候只管内存中的这份环境变量。
通过这个命令改的环境变量set bootdelay 3
只是把内存的那一份环境变量改成3了,Flash中的那一份根本就没有改。
如果你不保存到Flash中,下次开机的时候还是从Flash中去读取没有改的那一份。
怎么让Flash的那份环境变量也一起改了呢?
通过saveenv/save

2.1.6.2 保存环境变量的更改:saveenv/save
(1)saveenv/save命令不带参数,直接执行,作用是将内存中的环境变量的值同步保存
到Flash中环境变量的分区。注意:环境变量的保存是整体的覆盖保存,也就是说内存中
所有的环境变量都会整体的将Flash中环境变量分区中原来的内容整体覆盖。
不是说改了哪个就保存哪个。
所以你改一个环境变量和改10个环境变量保存起来是一模一样的,所以不用带参数。
为什么要这么设计呢?主要是因为我们的Flash是一个块设备

总结:彻底更改一个环境变量的值,需要2步:
第一步set命令来更改内存中的环境变量,第二步用save命令将其同步到Flash中环境变量的分区。
有时候我们只是测试一下这个环境变量,不希望影响到下一次开机,就用只set不save,
这样set后当前本次运行的uboot已经起效果了,只不过没有save下一次开机还是会恢复到原来的
状况。

2.1.6.3 网络测试指令:ping 
(1)命令用法:ping ip地址
注意:ping 是测试开发板和主机之间的网络链接,注意一下步骤:
1)首先要插上网线。
2)先试图ping通主机windows。注意windows中有线网卡的地址设置(设置本地连接)。
设置主机windows的本地连接IPv4地址为192.168.1.10
3)第三步确认开发板中uboot里几个网络相关的环境变量的值对不对,
ethaddr=00:00:23:34:45:66  //这个可以随便设置
netmask=255.255.255.0      //保存默认
ipaddr=192.168.1.10        //最主要是这个,这个环境变量表示当前开发板的IP地址
                           //这个地址必须和主机windows的IP地址在同一个网段。即前三段相同
网段的概念:一个IP地址分为2部分,一部分是网段地址,另一部分是网段内的主机地址
(由子网掩码来区分哪一部分是网段地址,哪一部分是IP地址)                           
set ipaddr 192.168.1.102

2.1.7 开发板和主机的ping通
2.1.7.1 开发板运行linux下和主机windows的ping通
2.1.7.2 开发板运行linux下和虚拟机ubuntu的ping通
(1)在Linux基础课中讲过:虚拟机的网卡设置可以选择好几种方式,常用的就是NAT和桥接(bridged)
(2)虚拟机要和开发板进行网络通信,只能通过桥接方式连接。
(3)虚拟机要想被开发板ping通,设置步骤如下:
第一步:虚拟机设置成桥接方式。
第二步:虚拟机的菜单中有个“虚拟网络编辑器”,这里面设置为桥接到有线网卡。(默认是自动的
,自动的一般会影响ping通。因为电脑现在一般都有2个网卡:一个有线的一个无线的。如果选了
自动,那么虚拟机会自动桥接到无线网卡上,但是我们确是通过有线网卡来连接开发板,自然ping
不通)
第三步:在虚拟机ubuntu中设置地址为192.168.1.141(可以通过/etc/network/interfaces文件来
设置静态的然后重启;也可以直接命令行ifconfig去设置)
  1 # interfaces(5) file used by ifup(8) and ifdown(8)
  2 auto lo
  3 iface lo inet loopback
  4 
auto ens33
#iface ens33 inet dhcp
iface ens33 inet static
address 192.168.1.141
netmask 255.255.255.0
gateway 192.168.1.1


//修改完成之后重启网卡
ifconfig ens33 down  
ifconfig ens33 up

再通过ifconfig查看ip地址就已经更改了


2.1.7.3 开发板运行uboot下和主机windows的ping通
(1)刚才开发板运行linux时和主机windows、虚拟机ubuntu都ping通了,说明
硬件和连接和主机设置没错。
(2)此时开发板重启进入uboot,设置好ipaddr、gatewayip,然后去ping windows发现还是
不通。怀疑uboot本身网络驱动有问题。
(3)然后同样情况下尝试去ping通虚拟机ubuntu,理论分析应该不通,但是实际发现是通的。


2.1.7.4 开发板运行uboot下和虚拟机ubuntu的ping通
(1)uboot和虚拟机ubuntu互相ping通(前提是虚拟机ubuntu设置为桥接,且桥接到有线网卡,且
ip地址设置正确的情况下)
结论:开发板中运行的uboot有点小bug,ping windows就不通,ping 虚拟机ubuntu就通。


2.1.8 uboot常用命令3
(1)uboot本身主要目标是启动内核,为了完成启动内核必须要能够部署内核,uboot为了部署内核
就需要将内核镜像从主机中下载过来然后烧录到本地flash中。uboot如何从主机(windows或者
虚拟机ubuntu)下载镜像到开发板上?有很多种方式,主流方式是fastboot和tftp。
fastboot的方式是通过USB线进行数据传输。(fastboot是近些年发展起来的技术,例如手机)
tftp的方式是通过有线网络的。典型的方式就是通过网络。
(2)tftp方式下载时实际上uboot扮演的是tftp客户端程序角色,主机windows或虚拟机ubuntu
中必须有一个tftp服务器,然后将要下载的镜像文件放在服务器的下载目录中,然后开发板中使用
uboot的tftp命令下载即可。实际上uboot的tftp命令就代表它背后的那个客户端。
(3)有些人习惯在windows中搭建tftp服务器,一般是用一些软件来搭建(譬如tftpd32),
这个软件一运行就在你的电脑上搭建了tftp服务器。使用起来比较简单。
有些人习惯在Linux下搭建tftp服务器。
(4)我的虚拟机搭建的时候设置的tftp下载目录是/tftpboot,将要被下载的镜像复制到这个目录下。
(5)检查开发板uboot的环境变量,注意serverip必须设置为虚拟机ubuntu的ip地址。
(serverip这个环境变量的意义就是主机tftp服务器的ip地址set serverip 192.168.1.141)

(6)然后在开发板的uboot下先ping通虚拟机ubuntu,然后再尝试下载:
tfpt 0x30000000 zImage-qt(意思是将服务器上名为zImage-qt的文件下载到开发板内存0x30000000
地址处)
(7)镜像下载到开发板的DDR中后,uboot就可以用movi指令进行镜像的烧写了。和网络就没有关系了

1)如果你是用的windows下的tftp服务器,那uboot的serverip就要设置为和windows下tftp服务器的
ip地址一样(windows下的tftp服务器软件设置的时候就有个步骤是让你设置服务器的ip地址,
这个ip地址和主机windows必须在一个网段)
2)整个过程中间环节比较多,实际做的时候可能最后会下载不下来。
bootm 0x82000000  //bootm这个命令是用来启动内核的

2.1.8.3 nfs启动内核命令:nfs
(1)uboot中也支持nfs命令,但是很少用


2.1.9 uboot的常用命令4
2.1.9.1 SD卡/iNand操作指令movi
(1)开发板如果用SD卡/EMMC/iNand等作为Flash,则在uboot中操作flash的指令为movi(或者mmc)
(2)movi指令是一个指令集
(3)movi的指令都是movi read和movi write一组的,movi read 用来读取iNand到DDR上,movi write一组的,movi
用来读取iNand到DDR上,movi write用来将DDR中的内容写入iNand中,理解这些指令时一定要注意涉及的2
个硬件:iNand和DDR内存。
(4)movi read {u-boot | kernel} {addr}
这个命令使用了一种通用型的描述方法来描述:movi和read外面没有任何标记说明每一次使用这个指令
都是必选的;一对大括号{}括起来的部分必选1个,大括号中的竖线表示多选一。中括号[]表示可选参数
(可以有也可以没有)
(5)指令有多种用法,譬如movi read u-boot 0x30000000,意思就是把iNand中的iNand中的u-boot
分区读出到DDR的0x3000000起始的位置处。(uboot代码中将iNand分成了很多分区,每个分区有地址范围和
分区名,uboot程序操作中可以使用直接地址来操作iNand分区,也可以使用分区名来操作分区。)
注意这里的0x30000000也可以直接写作3000000,意思是一样的(uboot的命令行中所有数字都被默认
当做十六进制处理,不管你加不加0x都一样)。

2.1.9.2 NandFlash操作指令nand
(1)理解方法和操作方法完全类似于movi指令
2.1.9.3 内存操作指令:mm、mw、md
(1)DDR中没有分区的(只听说过对硬盘、Flash进行分区,没听说过对内存进行分区...),但是
内存使用时要注意,千万不能越界踩到别人了,因为uboot是一个裸机程序,不像操作系统会由系统整体管理
所有内存,系统负责分配和管理,系统会保证内存不会随便越界。
裸机中程序中uboot并不管理所有内存,内存是散的随便用的,所以如果程序员(使用uboot的人)自己
不注意就可能出现自己把自己数据给覆盖了。(所以你思考下我们为什么把uboot放在23E00000地址处)
(2)md就是memory display, 用来显示内存中的内容的
用法:
md [.b, .w, .l]address [#of objects]

md.b 82000000
md.w 82000000
md.l 82000000

hisilicon # md.b 82000000
82000000: 04 a8 8f 02 d4 a1 a0 3e 04 00 00 00 03 b8 af 01    .......>........
82000010: d4 d9 60 3e 05 00 00 00 02 c8 ef 00 d2 11 21 3e    ..`>..........!>
82000020: 06 00 00 00 02 d4 2f 00 ce 51 e1 3d 07 00 00 00    ....../..Q.=....
82000030: 01 e4 7f 3f c9 91 a1 3d 08 00 00 00 01 f0 ef 3e    ...?...=.......>
一个字节一个字节的显示

hisilicon # md.w 82000000
82000000: a804 028f a1d4 3ea0 0004 0000 b803 01af    .......>........
82000010: d9d4 3e60 0005 0000 c802 00ef 11d2 3e21    ..`>..........!>
82000020: 0006 0000 d402 002f 51ce 3de1 0007 0000    ....../..Q.=....
82000030: e401 3f7f 91c9 3da1 0008 0000 f001 3eef    ...?...=.......>
82000040: d1c2 3d61 0009 0000 f801 3e5f 15bb 3d22    ..a=......_>.."=
82000050: 000a 0000 0800 3dd0 5db2 3ce2 000a 0000    .......=.].<....
82000060: 1000 3d60 a1a9 3ca2 000b 0000 1800 3cf0    ..`=...<.......<
82000070: e99e 3c72 000c 0000 2000 3ca0 3191 3c43    ..r<..... .<.1C<
两个字节两个字节的显示.

hisilicon # md.l 82000000
82000000: 028fa804 3ea0a1d4 00000004 01afb803    .......>........
82000010: 3e60d9d4 00000005 00efc802 3e2111d2    ..`>..........!>
82000020: 00000006 002fd402 3de151ce 00000007    ....../..Q.=....
82000030: 3f7fe401 3da191c9 00000008 3eeff001    ...?...=.......>
82000040: 3d61d1c2 00000009 3e5ff801 3d2215bb    ..a=......_>.."=
82000050: 0000000a 3dd00800 3ce25db2 0000000a    .......=.].<....
82000060: 3d601000 3ca2a1a9 0000000b 3cf01800    ..`=...<.......<
82000070: 3c72e99e 0000000c 3ca02000 3c433191    ..r<..... .<.1C<
82000080: 0000000d 3c602800 3c237983 0000000d    .....(`<.y#<....
82000090: 3c202c00 3bf3c176 0000000e 3bf03000    ., <v..;.....0.;
820000a0: 3be40967 0000000e 3bd03400 3bc45158    g..;.....4.;XQ.;
820000b0: 0000000e 3bc03800 3bc49547 0000000e    .....8.;G..;....
820000c0: 3bc03800 3bc4d936 0000000e e5dae002    .8.;6..;........
820000d0: e5daa003 e189980e e1899c0a e08dd000    ................
820000e0: e28da801 e3a05000 e28aa901 e154000a    .....P........T.
820000f0: 2a000016 e084a009 e28f9050 e15a0009    ...*....P.....Z.
四个字节四个字节的显示

每一行都是显示16个字节
hisilicon # md.b 82000000 10 只显示16个字节
82000000: 04 a8 8f 02 d4 a1 a0 3e 04 00 00 00 03 b8 af 01    .......>........

hisilicon # md.b 82000000 20 只显示32个字节
82000000: 04 a8 8f 02 d4 a1 a0 3e 04 00 00 00 03 b8 af 01    .......>........
82000010: d4 d9 60 3e 05 00 00 00 02 c8 ef 00 d2 11 21 3e    ..`>..........!>

(3)mw就是memory write ,将内容写到内存中
mw [.b, .w, .l] address value [count]

hisilicon # mw.b 82000000 55
(4)mm就是memory modify,修改内存中的某一块,内存的地址会自动增加到下一个
说白了还是写内存(如果需要批量的逐个写内存)
mm [.b, .w, .l] address
hisilicon # mm.b 82000000
82000000: 55 ? 11
82000001: a8 ?

hisilicon # mm.b 82000000
82000000: 55 ? 11
82000001: a8 ? 22
82000002: 8f ? y  输入y结束修改

2.1.9.4 启动内核指令:bootm、go
(1)uboot的终极目标就是启动内核,启动内核在uboot中表现为一个指令,uboot命令行
中调用这个指令就会启动内核(不管成功与否,所以这个指令是一条死路)
(2)差别:bootm启动内核同时给内核传参,而go命令启动内核不传参。
bootm其实才是正宗的启动内核的命令,一般情况下都用这个;go命令本来 不是专为启动
内核设计的,go命令内部其实就是一个函数指针指向一个内存地址然后直接调用那个函数,
go命令的实质就是PC直接跳转到一个内存地址去运行而已。
go命令可以用来在uboot中执行任何的裸机程序(有一种调试裸机程序的方法就是事先启动
uboot,然后在uboot中去下载裸机程序,用go命令去执行裸机程序)

2.1.10 uboot的常用环境变量1
2.1.10.1 如何理解环境变量
2.1.10.2 环境变量如何参与程序运行
(1)环境变量有2份,一份在Flash中,另一份在DDR中。
uboot开机时一次性从Flash中读取全部环境变量到DDR中作为环境变量的初始值,然后使用过程中
都是用DDR中这一份,用户可以用saveenv指令将DDR中的环境变量重新写入Flash中去更新Flash中
环境变量。下次开机时又会从Flash中再读一次。
(2)环境变量在uboot中是用字符串表示的,也就是说uboot是按照字符匹配的方式来区分各个环境
变量的。因此用的时候一定要注意不要打错字了。

set botdelay  //后面不加任何参数就可以删掉环境变量

2.1.10.3 自动运行倒数时间:bootdelay
2.1.10.4 网络设置:ipaddr serverip
(1)ipaddr是开发板的本地IP地址
(2)serverip是开发板通过tftp指令去tftp服务器下载东西时,tftp服务器的IP地址。
(3)gatewayip是开发板的本地网关地址
(4)netmask是子网掩码
(5)ethaddr是开发板的本地网卡的MAC地址。

2.1.11 uboot的常用环境变量2
2.1.11.1 自动运行命令设置:bootcmd
(1)uboot启动后会开机自动倒数bootdelay秒,如果没有人按下回车打断启动,
则uboot会自动执行启动命令来启动内核。
(2)uboot开机自动启动时实际就是在内部执行了bootcmd这个环境变量的值所对应的命令集。
(3)bootcmd=movi read kernel 30008000; bootm 30008000
意思是:将iNand的kernel分区读取到DDR的30008000地址处。
bootm 30008000 从内存的地址30008000启动内核
(4)set bootcmd printenv
然后saveenv;然后重启则会看到启动倒数后自动执行printenv命令后打印出环境变量。
这个小实验说明开机自动执行了bootcmd。bootcmd不一定非得用来启动内核,也可以干别的。
也可以把bootcmd设成别的值
hisilicon # set bootcmd printenv
那么倒计时完后就是打印环境变量,而不是启动内核
set bootcmd 'sf probe 0;sf read 0x82000000 0x100000 0x300000;bootm 0x82000000'
命令里面有分号,整个命令一定要单引号引起来。

注意:可以手工输入执行sf probe 0;sf read 0x82000000 0x100000 0x300000;bootm 0x82000000
不一定要开始自动启动。

2.1.11.2 uboot给kernel传参:bootargs
(1)linux内核启动时可以接收uboot给他传递的启动参数,这些启动参数是uboot和内核约定好的形式、内容
,Linux内核在这些启动参数的指导下完成启动过程。这样的设计是为了灵活,为了内核在不重新编译的
情况下可以用不同的方式启动。
(2)我们要做的事情就是:在uboot的环境变量中设置bootargs,然后bootm命令启动内核时会自动将
bootargs传给内核。
(3)bootargs=mem=32M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1024K(boot),3072K(kernel),12288K(rootfs)
这个启动内核传参的参数一定是内核和uboot约定好的
不同的参数通过空格隔开了
console=ttyAMA0,115200 控制台使用串口0,波特率115200
root=/dev/mtdblock2    根文件系统使用mtdblock2  
rootfstype=jffs2       根文件系统的类型是jffs2   
(4)内核传参非常重要。在内核移植的时候,新手经常因为忘记给内核传参,或者给内核传递的参数不对,
造成内核启动不起来。

2.1.11.3 新建、更改、删除一个环境变量的方法
(1)新建一个环境变量,使用set var value
(2)更改一个环境变量,使用set var value
(3)删除一个环境变量,使用set var

2.1.11.4 注意:环境变量更改后的保存
(1)修改完成环境变量后一定要保存,否则下次开机更改就没了


 

这篇关于uboot和系统移植-第1部分-2.1 uboot学习前传的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/821466

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]