Linux系统uboot、linux kernel、rootfs移植学习笔记(一)

目录

一、u-boot使用实验

1.u-boot简介

2.u-boot初次编译

3.u-boot烧写与启动

4.u-boot命令使用

4.1 信息查询命令

 4.2 环境变量操作命令

(1)修改环境变量

 (2)新建环境变量

 (3)删除环境变量

 4.3 内存操作命令

(1)md命令

(2)nm命令

 (3)mm命令

(4)mw命令

 (5)cp命令

 (6)cmp命令

4.4 网络操作命令

(1)ping命令

(2)dhcp命令

(3)nfs命令

(4)tftp命令

 4.5 EMMC和SD卡操作命令

(1)mmc info命令

 (2)mmc rescan命令

(3)mmc list命令

(4)mmc dev命令

 (5)mmc part命令

(6)mmc read命令

 (7)mmc write命令

 (8)mmc erase命令

 4.6 FAT 格式文件系统操作命令

(1)fatinfo命令

 (2)fatls命令

(3)fstype命令 

(4)fatload命令 

(5) fatwrite命令

 4.7 EXT 格式文件系统操作命令

 4.8 BOOT操作命令

(1)bootz命令

 (2)bootm命令

(3)boot命令

 4.9 其他常用操作命令

(1)reset命令

(2) go命令

(3)run命令

(4)mtest命令

一、u-boot使用实验

1.u-boot简介

       Linux系统要启动就必须需要一个bootloader程序,也就说芯片上电以后先运行一段bootloader程序。这段bootloader程序会先初始化DDR等外设,然后将Linux内核flash(NAND,NOR FLASH,SD,MMC等)拷贝到DDR中,最后启动Linux内核。当然了,bootloader的实际工作要复杂的多,但是它最主要的工作就是启动Linux内核,bootloader和Linux内核的关系就跟PC上的BIOS和Windows的关系一样,bootloader就相当于BIOS。目前有很多现成的bootloader软件可以使用,比如U-Boot、vivi、RedBoot等等,其中以U-Boot使用最为广泛。(DDR是"Double Data Rate"的缩写,指的是双倍数据速率。)uboot官网为 http://www.denx.de/wiki/U-Boot/。

2.u-boot初次编译

首先在Ubuntu中安装ncurses 库,否则编译会报错,安装命令如下:

sudo apt-get install libncurses5-dev

将正点原子uboot和linux出厂源码uboot-imx-2016.03-2.1.0-g0ae7e33-v1.7.tar.bz2拷贝到ubuntu中并解压

tar -vxjf uboot-imx-2016.03-2.1.0-g0ae7e33-v1.7.tar.bz2

 解压参数说明

  • tar:是一个用于创建、查看和提取归档文件的命令行工具。
  • -v:表示"verbose",即在解压缩过程中显示详细信息,包括被解压缩的文件名。
  • -x:表示"extract",即从归档文件中提取文件。
  • -j:表示使用bzip2算法进行解压缩。bzip2是一种高压缩比的压缩算法,通常用于解压缩.bz2格式的压缩文件。
  • -f:表示后面紧跟着要解压缩的归档文件的名称。

路径如下:

在alientek_uboot文件夹创建shell脚本文件mx6ull_alientek_emmc.sh进行uboot编译

#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4

第 1行是 shell脚本要求的,必须是“#!/bin/bash”或者“#!/bin/sh”

第 2行使用了 make命令,用于清理工程,也就是每次在编译 uboot之前都清理一下工程。这里的 make命令带有三个参数,第一个是 ARCH,也就是指定架构,这里肯定是 arm;第二个参数CROSS_COMPILE,用于指定编译器,只需要指明编译器前缀就行了,比如arm-linux- gnueabihf-gcc编译器的前缀就是“arm-linux-gnueabihf-”;最后一个参数distclean就是清除工程

第 3行也使用了make命令,用于配置uboot。同样有三个参数,不同的是,最后一个参数是 mx6ull_14x14_ddr512_emmc_defconfig。前面说了uboot是 bootloader 的一种,可以用来引导 Linux,但是uboot除了引导Linux以外还可以引导其它的系统,而且uboot还支持其它的架构和外设,比如USB、网络、SD卡等。这些都是可以配置的,需要什么功能就使能什么功能。所以在编译uboot之前,一定要根据自己的需求配置uboot。mx6ull_14x14_ddr512_emmc_defconfig就是正点原子针对I.MX6U-ALPHA的 EMMC核心板编写的配置文件,这个配置文件在uboot源码的configs目录中。在uboot中,通过“make xxx_defconfig”来配置uboot,xxx_defconfig就是不同板子的配置文件,这些配置文件都在 uboot/configs目录中。

第4行有4个参数,用于编译 uboot,通过第3行配置好 uboot 以后就可以直接“make”编译 uboot 了。其中 V=1用于设置编译过程的信息输出级别-j用于设置主机使用多少线程编译uboot,最好设置成我们虚拟机所设置的核心数,如果在VMware里面给虚拟就分配了4个核,那么使用-j4是最合适的,这样4个核都会一起编译。

使用chmod命令给予mx6ull_alientek_emmc.sh 文件可执行权限

chmod 777 mx6ull_alientek_emmc.sh

chmod命令介绍:

在 Unix、Linux 和类似的操作系统中,文件和目录都有权限属性,用于控制对它们的访问和操作。这些权限属性分为三个类别:所有者(Owner)、所属组(Group)和其他用户(Others)。

chmod 命令通过指定不同的权限参数来修改文件或目录的权限。常用的权限参数包括:

  • u:表示所有者(Owner)的权限。
  • g:表示所属组(Group)的权限。
  • o:表示其他用户(Others)的权限。
  • a:表示所有用户(包括所有者、所属组和其他用户)的权限。

权限参数后面可以跟上符号操作和权限操作的组合,常见的符号操作包括:

  • +:添加权限。
  • -:移除权限。
  • =:设置权限。

常见的权限操作包括:

  • r:读权限(Read)。
  • w:写权限(Write)。
  • x:执行权限(Execute)。

chmod 命令还可以使用数字表示权限,每个权限用一个数字表示,其中读权限为 4,写权限为 2,执行权限为 1。通过将这些数字相加,可以得到所需的权限组合。例如,chmod 755 file.txt 表示将 file.txt 文件的权限设置为 -rwxr-xr-x,即所有者具有读、写和执行权限,而所属组和其他用户具有读和执行权限。

然后就可以使用这个shell脚本文件来重新编译uboot,命令如下:

./mx6ull_alientek_emmc.sh

3.u-boot烧写与启动

uboot编译好以后就可以烧写到板子上使用了,将uboot烧写到SD卡中,然后通过SD卡启动来运行 uboot。使用imxdownload软件烧写,命令如下:

chmod 777 imxdownload //给予imxdownload可执行权限,一次即可
./imxdownload u-boot.bin /dev/sdb //烧写到SD卡,不能烧写到/dev/sda或sda1设备里面!

 烧写完成后,将SD卡插到开发板上,设置拨码开关为SD卡启动,将USB线将USB_TTL与电脑连接,打开MobaXterm软件。复位开发板,在3秒倒计时期间按下回车键进入uboot的命令行模式。

4.u-boot命令使用

进入 uboot 的命令行模式以后输入“help”或者“?”,然后按下回车即可查看当前 uboot 所支持的命令。

 输入如下命令即可查看“bootz”这个命令的用法:

4.1 信息查询命令

常用的和信息查询有关的命令有 3 个:bdinfo、printenv 和 version。先来看一下 bdinfo 命令,此命令用于查看板子信息,直接输入“bdinfo”即可

从上图 中可以得出 DRAM 的起始地址和大小、启动参数保存起始地址、波特率、sp(堆栈指针)起始地址等信息。

命令“printenv”用于输出环境变量信息,uboot 也支持 TAB 键自动补全功能,输入“print” 然后按下 TAB 键就会自动补全命令,直接输入“print”也可以。输入“print”,然后按下回车键,环境变量如下图所示:

 命令 version 用于查看 uboot 的版本号

从上图可以看出,当前 uboot 版本号为 2016.03,2023 年 8 月 27 日编译的,编译器为arm-linux-gnueabihf-gcc,这是 NXP 官方提供的编译器,正点原子出厂系统用的此编译器编译的,但是本教程我们统一使用 arm-linux-gnueabihf-gcc。

 4.2 环境变量操作命令

(1)修改环境变量

环境变量的操作涉及到两个命令:setenv 和 saveenv,命令 setenv 用于设置或者修改环境变量的值。命令 saveenv  用于保存修改后的环境变量,一般环境变量是存放在外部 flash中的,uboot 启动的时候会将环境变量从flash 读取到DRAM 中。所以使用命令 setenv 修改的是DRAM中的环境变量值,修改以后要使用 saveenv 命令将修改后的环境变量保存到flash中,否则的话uboot 下一次重启会继续使用以前的环境变量值。

比如我们要将环境变量 bootdelay 改为 5,就可以使用如下所示命令:

setenv bootdelay 5
saveenv

执行结果如下: 

在上图中,当我们使用命令 saveenv 保存修改后的环境变量的话会有保存过程提示信息,根据提示可以看出环境变量保存到了 MMC(0)中,也就是 SD 卡中。因为我们现在将 uboot 烧写到了 SD  卡里面,所以会保存到 MMC(0)中。如果烧写到 EMMC  里面就会提示保存到MMC(1),也就是 EMMC 设备。

 修改 bootdelay 以后,重启开发板,uboot 就是变为 5 秒倒计时,如下图所示:

有时候修改的环境变量值可能会有空格,比如 bootcmd、bootargs 等,这个时候环境变量值就得用单引号括起来,比如下面修改环境变量 bootargs 的值:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' 
saveenv
 (2)新建环境变量

命令 setenv 也可以用于新建命令,用法和修改环境变量一样,比如我们新建一个环境变量author,author 的值为我的名字拼音:ssz,那么就可以使用如下命令:

setenv author ssz
saveenv

 (3)删除环境变量

既然可以新建环境变量,肯定也可以删除环境变量,删除环境变量也是使用命令 setenv, 要删除一个环境变量只要给这个环境变量赋空值即可,比如删除掉上面新建的author 这个环境变量,命令如下:

setenv author
saveenv

 4.3 内存操作命令

内存操作命令就是用于直接对 DRAM是动态随机存取存储器(Dynamic Random Access Memory)的缩写,是一种计算机内存类型。它是一种用于临时存储数据的半导体存储器,广泛应用于计算机系统、移动设备和其他电子设备中。) 进行读写操作的,常用的内存操作命令有md、nm、mm、mw、cp 和cmp

(1)md命令

md 命令用于显示内存值,格式如下:

md[.b, .w, .l] address [# of objects]

命令中的[.b .w .l]对应byte、word和long,也就是分别以1个字节、2个字节、4个字节来显示内存值。address就是要查看的内存起始地址[# of objects]表示要查看的数据长度,这个数据长度单位不是字节,而是跟你所选择的显示格式有关。比如你设置要查看的内存长度为20(十六进制为0x14),如果显示格式为.b的话那就表示20个字节;如果显示格式为.w的话就表示 20个word,也就是20*2=40个字节;如果显示格式为.l的话就表示20个 long,也就是20*4=80个字节。另外要注意:uboot 命令中的数字都是十六进制的!不是十进制的!

比如你想查看以 0X80000000 开始的 20 个字节的内存值,显示格式为.b 的话,应该使用如下所示命令:

md.b 80000000 14

而不是:

md.b 80000000 20
(2)nm命令

nm 命令用于修改指定地址的内存值,命令格式如下:

nm [.b, .w, .l] address

nm命令同样可以以.b、.w 和.l 来指定操作格式,比如现在以.l 格式修改0x80000000地址的数据为 0x12345678。输入命令:

bfffffff表示地址 0x80000000 现在的数据,?后面就可以输入要修改后的数据 0x12345678,输入完成以后按下回车,然后再输入‘q’即可退出.

修改完成以后在使用命令 md 来查看一下有没有修改成功,如上图所示。

 (3)mm命令

mm 命令也是修改指定地址内存值的,使用 mm 修改内存值的时候地址会自增,而使用命令 nm 的话地址不会自增。比如以.l 格式修改从地址 0x80000000 开始的连续 3 个内存块(3*4=12 个字节)的数据为 0X05050505,操作如下图所示:

从上图可以看出,修改了地址 0X80000000、0X80000004 和 0X80000008 的内容为0x05050505。使用命令 md 查看修改后的值,结果如下图 所示:

 

(4)mw命令

命令 mw 用于使用一个指定的数据填充一段内存,命令格式如下:

mw [.b, .w, .l] address value [count]

 mw 命令同样可以以.b、.w 和.l来指定操作格式,address 表示要填充的内存起始地址,value为要填充的数据,count 是填充的长度。比如使用.l 格式将以 0X80000000 为起始地址的 0x10 个内存块(0x10 * 4=64 字节)填充为 0X0A0A0A0A,命令如下:

 (5)cp命令

cp 是数据拷贝命令,用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 Nor Flash 中的数据拷贝到DRAM 中。命令格式如下:

cp [.b, .w, .l] source target count

 cp 命令同样可以以.b、.w 和.l 来指定操作格式,source 为源地址,target 为目的地址,count为拷贝的长度。我们使用.l 格式将 0x80000000 处的地址拷贝到 0X80000100 处,长度为 0x10 个内存块(0x10 * 4=64 个字节),命令如下所示:

 (6)cmp命令

cmp 是比较命令,用于比较两段内存的数据是否相等,命令格式如下:

cmp [.b, .w, .l] addr1 addr2 count

cmp 命令同样可以以.b、.w 和.l 来指定操作格式,addr1 为第一段内存首地址,addr2 为第二段内存首地址,count 为要比较的长度。我们使用.l 格式来比较 0x80000000 和 0X80000100这两个地址数据是否相等,比较长度为 0x10 个内存块(16 * 4=64 个字节),命令如下所示:

4.4 网络操作命令

uboot是支持网络的,我们在移植 uboot 的时候一般都要调通网络功能,因为在移植 linux kernel 的时候需要使用到uboot 的网络功能做调试。uboot 支持大量的网络相关命令,比如 dhcp、ping、nfs 和 tftpboot。

开发板和PC主机用网线连接,连接网口2,设置环境变量

环境变量描述
ipaddr

开发板ip地址,可以不设置,使用dhcp命令来从路由器获取IP地址。

ethaddr

开发板的MAC地址,一定要设置。

gatewayip网关地址
netmask子网掩码
serverip

服务器IP地址,也就是Ubuntu主机IP地址,用于调试代码。

setenv ipaddr 192.168.1.55 
setenv ethaddr b8:ae:1d:01:00:00 
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.66
saveenv
(1)ping命令

开发板的网络能否使用,是否可以和服务器(Ubuntu 主机)进行通信,通过 ping 命令就可以验证,直接 ping 服务器的 IP 地址即可,比如我的服务器 IP 地址为 192.168.1.66,命令如下:

(2)dhcp命令

dhcp 用于从路由器获取 IP 地址,前提得开发板连接到路由器上的,如果开发板是和电脑直连的,那么 dhcp 命令就会失效,直接输入 dhcp 命令即可通过路由器获取到 IP 地址,我的开发板与电脑连接,这里不予展示

(3)nfs命令

后面进行Linux 驱动开发的时候需要NFS 启动,因此要先安装并开启Ubuntu 中的NFS 服务,使用如下命令安装NFS 服务:

先检查看是否安装:

dpkg -s nfs-kernel-server 

如果没安装,执行下面命令进行安装: 

sudo apt-get install nfs-kernel-server rpcbind

等待安装完成,安装完成以后在用户根目录下创建一个名为“linux”的文件夹,以后所有的东西都放到这个“linux”文件夹里面,在“linux”文件夹里面新建一个名为“nfs”的文件夹,如下图所示:

上图创建的nfs 文件夹供nfs 服务器使用,以后我们可以在开发板上通过网络文件系统来访问nfs 文件夹,要先配置nfs,使用如下命令打开nfs 配置文件/etc/exports:

sudo vi /etc/exports

打开/etc/exports 以后在后面添加如下所示内容:

 /home/ssz/linux/nfs *(rw,sync,no_root_squash)

# /etc/exports: the access control list for filesystems which may be exported
#		to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#
/home/ssz/linux/nfs *(rw,sync,no_root_squash)

重启NFS 服务,使用命令如下:

sudo /etc/init.d/nfs-kernel-server restart

注:ubuntu17.10之后的版本nfs默认只支持协议3和4,但后续我们使用的uboot默认使用协议2,所以需要在/etc/default/nfs-kernel-server文件末尾加一句内容:

RPCNFSDOPTS=‘“--nfs-version 2,3,4 --debug --syslog” 

然后重启nfs服务即可。

nfs(Network File System)网络文件系统,通过 nfs 可以在计算机之间通过网络来分享资源, 比如我们将 linux 镜像和设备树文件放到Ubuntu 中,然后在 uboot 中使用 nfs 命令将 Ubuntu 中的 linux 镜像和设备树下载到开发板的DRAM中。这样做的目的是为了方便调试 linux 镜像和设备树,也就是网络调试,通过网络调试是 Linux 开发中最常用的调试方法。 

原因是嵌入式 linux 开发不像单片机开发,可以直接通过 JLINK 或 STLink 等仿真器将代码直接烧写到单片机内部的 flash 中,嵌入式Linux 通常是烧写到 EMMC、NAND Flash、SPI Flash 等外置 flash 中,但是嵌入式 Linux 开发也没有 MDK,IAR 这样的IDE,更没有烧写算法,因此不可能通过点击一个“download”按钮就将固件烧写到外部 flash 中。

虽然半导体厂商一般都会提供一个烧写固件的软件,但是这个软件使用起来比较复杂,这个烧写软件一般用于量产的。其远没有 MDK、IAR 的一键下载方便,在 Linux 内核调试阶段,如果用这个烧写软件的话将会非常浪费时间,而这个时候网络调试的优势就显现出来了,可以通过网络将编译好的 linux 镜像和设备树文件下载到 DRAM 中,然后就可以直接运行

我们一般使用 uboot 中的nfs命令将Ubuntu中的文件下载到开发板的DRAM中,在使用之前需要开启Ubuntu主机的NFS服务,并且要新建一个NFS使用的目录,以后所有要通过NFS访问的文件都需要放到这个NFS目录中,uboot 中的 nfs 命令格式如下所示:

nfs [loadAddress] [[hostIPaddr:]bootfilename]

loadAddress 是要保存的 DRAM 地址,[[hostIPaddr:]bootfilename]是要下载的文件地址,将出厂系统镜像的kernel镜像文件zimage文件放到nfs目录下

准备好以后就可以使用 nfs 命令来将 zImage 下载到开发板 DRAM 的 0X80800000 地址处, 命令如下:

  

(4)tftp命令

tftp命令的作用和 nfs 命令一样,都是用于通过网络下载东西到 DRAM 中,只是 tftp 命令使用的 TFTP 协议,Ubuntu 主机作为 TFTP 服务器。因此需要在 Ubuntu 上搭建 TFTP 服务器, 需要安装 tftp-hpa 和 tftpd-hpa,命令如下:

sudo apt-get install tftp-hpa tftpd-hpa 
sudo apt-get install xinetd

和 NFS 一样,TFTP 也需要一个文件夹来存放文件,在用户目录下新建一个目录,命令如下

mkdir /home/ssz/linux/tftpboot
chmod 777 /home/ssz/linux/tftpboot

最后配置 tftp,安装完成以后新建文件/etc/xinetd.d/tftp,如果没有/etc/xinetd.d 目录的话自行创建,然后在里面输入如下内容:

server tftp
{
  socket_type = dgram
  protocol = udp
  wait = yes
  user = root
  server = /usr/sbin/in.tftpd
  server_args = -s /home/ssz/linux/tftpboot/
  disable = no
  per_source = 11
  cps = 100 2
  flags = IPv4
 }

 完了以后启动 tftp 服务,命令如下:

sudo service tftpd-hpa start	

 打开/etc/default/tftpd-hpa 文件,将其修改为如下所示内容:

# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/home/ssz/linux/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="-l -c -s"

 TFTP_DIRECTORY 就是我们上面创建的 tftp 文件夹目录,以后我们就将所有需要通过TFTP 传输的文件都放到这个文件夹里面,并且要给予这些文件相应的权限。最后输入如下命令, 重启 tftp 服务器:

sudo service tftpd-hpa restart

 将 zImage 镜像文件拷贝到 tftpboot 文件夹中,并且给予 zImage 相应的权限

uboot 中的 tftp 命令格式如下:

tftpboot [loadAddress] [[hostIPaddr:]bootfilename]

看起来和nfs命令格式一样的,loadAddress是文件在DRAM中的存放地址,[[hostIPaddr:]bootfilename]是要从Ubuntu 中下载的文件。但是和 nfs 命令的区别在于,tftp 命令不需要输入文件在Ubuntu 中的完整路径,只需要输入文件名即可。比如我们现在将 tftpboot 文件夹里面的zImage 文件下载到开发板 DRAM 的 0X80800000 地址处,命令如下:

 4.5 EMMC和SD卡操作命令

uboot 支持 EMMC 和 SD 卡,因此也要提供 EMMC 和 SD 卡的操作命令。一般认为 EMMC和 SD 卡是同一个东西,所以没有特殊说明,本教程统一使用 MMC 来代指 EMMC 和 SD 卡。uboot 中常用于操作 MMC 设备的命令为“mmc”。

命令

描述

mmc info

输出 MMC 设备信息

mmc read

读取 MMC 中的数据。

mmc wirte

向 MMC 设备写入数据。

mmc rescan

扫描 MMC 设备。

mmc part

列出 MMC 设备的分区。

mmc dev

切换 MMC 设备。

mmc list

列出当前有效的所有 MMC 设备。

mmc hwpartition

设置 MMC 设备的分区。

mmc bootbus……

设置指定 MMC 设备的 BOOT_BUS_WIDTH 域的值。

mmc bootpart……

设置指定 MMC 设备的 boot 和 RPMB 分区的大小。

mmc partconf……

设置指定 MMC 设备的 PARTITION_CONFG 域的值。

mmc rst

复位 MMC 设备

mmc setdsr

设置 DSR 寄存器的值。

(1)mmc info命令

mmc info 命令用于输出当前选中的 mmc info 设备的信息

 (2)mmc rescan命令

mmc rescan 命令用于扫描当前开发板上所有的 MMC 设备,包括 EMMC 和 SD 卡,输入“mmc rescan”即可。

(3)mmc list命令

mmc  list 命令用于来查看当前开发板一共有几个 MMC 设备

(4)mmc dev命令

mmc dev 命令用于切换当前 MMC 设备,命令格式如下:

mmc dev [dev] [part]

 [dev]用来设置要切换的 MMC 设备号,[part]是分区号。如果不写分区号的话默认为分区 0。使用如下命令切换到 SD 卡:

mmc dev 0	//切换到 SD 卡,0 为 SD 卡,1 为 eMMC

 

 (5)mmc part命令

有时候 SD 卡或者 EMMC 会有多个分区,可以使用命令“mmc part”来查看其分区,比如查看 EMMC 的分区情况,输入如下命令:

mmc dev 1	//切换到 EMMC 
mmc part	//查看 EMMC 分区

 

从上图中可以看出,此时 EMMC 有两个分区,第一个分区起始扇区为 20480,长度为1024000个扇区;第二个分区起始扇区为 1228800,长度为 14041088个扇区。

如果 EMMC 里面烧写了 Linux 系统的话,EMMC 是有 3 个分区的,第 0 个分区存放 uboot第 1 个分区存放Linux 镜像文件和设备树第 2 个分区存放根文件系统

但是在上图中只有两个分区,那是因为第 0 个分区没有格式化,所以识别不出来,实际上第 0 个分区是存在的。一个新的 SD卡默认只有一个分区,那就是分区 0,所以前面讲解的 uboot 烧写到SD 卡,其实就是将 u-boot.bin烧写到了 SD 卡的分区 0 里面。

如果要将 EMMC 的分区 2 设置为当前 MMC 设备,可以使用如下命令:

mmc dev 1 2
(6)mmc read命令

 mmc read 命令用于读取 mmc 设备的数据,命令格式如下:

mmc read addr blk# cnt

 addr 是数据读取到 DRAM 中的地址,blk 是要读取的块起始地址(十六进制),一个块是 512字节,这里的块和扇区是一个意思,在 MMC 设备中我们通常说扇区,cnt 是要读取的块数量(十六进制)。比如从 EMMC 的第 1536(0x600)个块开始,读取 16(0x10)个块的数据到 DRAM 的

0X80800000 地址处,命令如下:

 这里我们还看不出来读取是否正确,通过 md.b 命令查看 0x80800000 处的数据就行了,查看 16*512=8192(0x2000)个字节的数据,命令如下

md.b 80800000 2000
 (7)mmc write命令

mmc read命令用于读取 mmc 设备的数据,命令格式如下:

mmc write addr blk# cnt

addr是要写入 MMC 中的数据在 DRAM 中的起始地址,blk是要写入 MMC 的块起始地址 (十六进制),cnt 是要写入的块大小,一个块为 512 字节。我们可以使用命令“mmc write”来升级 uboot,也就是在 uboot 中更新 uboot。这里要用到nfs 或者 tftp 命令,通过 nfs 或者 tftp 命令将新的 u-boot.bin 下载到开发板的 DRAM 中,然后再使用命令“mmc write”将其写入到 MMC 设备中。我们就来更新一下 SD 中的 uboot,先查看一下 SD 卡中的 uboot 版本号,注意编译时间,输入命令:

可以看出当前 SD 卡中的 uboot 是 2023 年 8 月 27 日 17:38:18 编译的。我们现在重新编译一下 uboot,然后将编译出来的 u-boot.imx(u-boot.bin 前面加了一些头文件)拷贝到 Ubuntu 中的tftpboot 目录下。最后使用 tftp 命令将其下载到 0x80800000 地址处,命令如下:

可以看出,u-boot.imx 大小为 363520 字节,363520/512=710,所以我们要向 SD 卡中写入742 个块,如果有小数的话就要加 1 个块。使用命令“mmc write”从 SD 卡分区 0 第 2 个块(扇区)开始烧写,一共烧写 710(0x2C6)个块,命令如下:

烧写成功,重启开发板(从 SD 卡启动),重启以后再输入 version 来查看版本号,结果如下图所示:

从上图可以看出,此时的 uboot 是 20203年 8月 27 号 22:56:39 编译的,说明 uboot 更新成功。这里我们就学会了如何在SD卡 uboot 中更新 uboot 了,如果要更新 EMMC 中的 uboot 也是一样的。

同理,如果要在 uboot 中更新 EMMC 对应的 uboot,可以使用如下所示命令:

 把拨码开关移动至EMMC启动,重启开发板就可以看到uboot日期改变

 (8)mmc erase命令

 如果要擦除 MMC 设备的指定块就是用命令“mmc erase”,命令格式如下:

mmc erase blk# cnt

 blk 为要擦除的起始块,cnt 是要擦除的数量。没事不要用 mmc erase 来擦除 MMC 设备!!!

 4.6 FAT 格式文件系统操作命令

有时候需要在 uboot 中对 SD 卡或者 EMMC 中存储的文件进行操作,这时候就要用到文件操作命令,跟文件操作相关的命令有:fatinfo、fatls、fstype、fatload 和 fatwrite,但是这些文件操作命令只支持 FAT 格式的文件系统!!

(1)fatinfo命令

 fatinfo 命令用于查询指定 MMC 设备分区的文件系统信息,格式如下:

fatinfo <interface> [<dev[:part]>]

 interface 表示接口,比如 mmc,dev 是查询的设备号,part 是要查询的分区。比如我们要查

询 EMMC 分区 1 的文件系统信息,命令如下:

从上图可以看出,EMMC 分区 1 的文件系统为 FAT32 格式的。 

 (2)fatls命令

 fatls 命令用于查询 FAT 格式设备的目录和文件信息,命令格式如下:

fatls <interface> [<dev[:part]>] [directory]

interface 是要查询的接口,比如 mmc,dev 是要查询的设备号,part 是要查询的分区,directory

是要查询的目录。比如查询 EMMC 分区 1 中的所有的目录和文件,输入命令: 

 从上图可以看出,emmc 的分区 1 中存放着 2 个文件。

(3)fstype命令 

 fstype 用于查看 MMC 设备某个分区的文件系统格式,命令格式如下:

 fstype <interface> <dev>:<part>

正点原子 EMMC 核心板上的 EMMC 默认有 3 个分区,我们来查看一下这三个分区的文件系统格式,输入命令:

从上图可以看出,分区 0 格式未知,因为分区 0 存放的 uboot,并且分区 0 没有格式化,所以文件系统格式未知。分区 1 的格式为 fat,分区 1 用于存放 linux 镜像和设备树。分区 2 的格式为 ext4,用于存放 Linux 的根文件系统(rootfs)

(4)fatload命令 

fatload 命令用于将指定的文件读取到 DRAM 中,命令格式如下: 

 fatload <interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]

interface 为接口,比如 mmc,dev 是设备号,part 是分区,addr 是保存在 DRAM 中的起始地址,filename 是要读取的文件名字。bytes 表示读取多少字节的数据,如果 bytes 为 0 或者省略的话表示读取整个文件。pos 是要读的文件相对于文件首地址的偏移,如果为 0 或者省略的话表示从文件首地址开始读取。我们将 EMMC 分区 1 中的 zImage 文件读取到 DRAM 中的0X80800000 地址处,命令如下:

(5) fatwrite命令

注意!uboot 默认没有使能 fatwrite 命令,需要修改板子配置头文件,比如 mx6ullevk.h、 mx6ull_alientek_emmc.h 等等,板子不同,其配置头文件也不同。找到自己开发板对应的配置头文件然后添加如下一行宏定义来使能fatwrite 命令:

#define CONFIG_FAT_WRITE	/* 使能 fatwrite 命令 */

fatwirte 命令用于将DRAM 中的数据写入到 MMC 设备中,命令格式如下

fatwrite <interface> <dev[:part]> <addr> <filename> <bytes>

interface 为接口,比如 mmc,dev 是设备号,part 是分区,addr 是要写入的数据在 DRAM中的起始地址,filename 是写入的数据文件名字,bytes 表示要写入多少字节的数据。我们可以通过 fatwrite 命令在 uboot 中更新 linux 镜像文件和设备树。我们以更新 linux 镜像文件 zImage 为例,首先将正点原子 I.MX6U-ALPHA  开发板提供的 zImage  镜像文件拷贝到 Ubuntu  中的tftpboot 目录下。

拷贝完成以后使用命令 tftp 将zImage 下载到DRAM 的 0X80800000 地址处,命令如下:

zImage 大小为 6785480(0X6789c8)个字节(注意,由于开发板系统在不断的更新中,因此zImage 大小不是固定的,一切以实际大小为准),接下来使用命令 fatwrite 将其写入到 EMMC 的分区 1 中,文件名字为 zImage,命令如下:

完成以后使用“fatls”命令查看一下EMMC 分区 1 里面的文件

 4.7 EXT 格式文件系统操作命令

uboot 有 ext2 和 ext4 这两种格式的文件系统的操作命令,常用的就四个命令,分别为ext2load、ext2ls、ext4load、ext4ls 和ext4write。这些命令的含义和使用与 fatload、fatls 和 fatwrite 一样,只是 ext2 和 ext4 都是针对 ext 文件系统的。比如 ext4ls 命令,EMMC 的分区 2 就是ext4 格式的,使用 ext4ls 就可以查询 EMMC 的分区 2 中的文件和目录,输入命令:

 4.8 BOOT操作命令

uboot 的本质工作是引导 Linux,所以 uboot 肯定有相关的 boot(引导)命令来启动 Linux。常用的跟 boot 有关的命令有:bootz、bootm 和 boot。

(1)bootz命令

要启动 Linux,需要先将 Linux 镜像文件拷贝到 DRAM 中,如果使用到设备树的话也需要将设备树拷贝到 DRAM 中。可以从 EMMC存储设备中将Linux 镜像和设备树文件拷贝到 DRAM,也可以通过 nfs 或者 tftp 将 Linux 镜像文件和设备树文件下载到 DRAM 中。不管用那种方法,只要能将 Linux 镜像和设备树文件存到 DRAM 中就行,然后使用 bootz 命令来启动,bootz 命令用于启动 zImage 镜像文件,bootz 命令格式如下:

bootz [addr [initrd[:size]] [fdt]]

命令 bootz 有三个参数,addr 是 Linux 镜像文件在 DRAM 中的位置,initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘-’代替即可,fdt 就是设备树文件在DRAM 中的地址。现在我们使用网络和EMMC 两种方法来启动 Linux 系统,首先将I.MX6U-ALPHA 开发板的 Linux 镜像和设备树发送到 Ubuntu 主机中的 tftpboot 文件夹下。Linux 镜像文件前面已经放到了 tftpboot 文件夹中,现在把设备树文件放到 tftpboot 文件夹里面。

Linux 镜像文件和设备树都准备好了,我们先学习如何通过网络启动 Linux,使用 tftp 命令将zImage 下载到DRAM 的0X80800000 地址处,然后将设备树imx6ull-14x14-emmc-4.3-800x480- c.dtb 下载到 DRAM 中的 0X83000000 地址处,最后之后命令 bootz 启动,命令如下:

上图就是我们通过 tftp 和 bootz 命令来从网络启动 Linux 系统,如果我们要从 EMMC 中启动Linux 系统的话只需要使用命令fatload 将zImage 和imx6ull-14x14-emmc-4.3-800x480-c.dtb 从EMMC 的分区 1 中拷贝到 DRAM 中,然后使用命令 bootz 启动即可。先使用命令 fatls 查看要下 EMMC 的分区 1 中有没有 Linux 镜像文件和设备树文件,如果没有的话参考前面的 fatwrite 命令将 tftpboot 中的 zImage 和 imx6ull-14x14-emmc-4.3-800x480-c.dtb 文件烧写到EMMC 的分区 1 中。

然后使用命令 fatload 将zImage 和imx6ull-14x14-emmc-4.3-800x480-c.dtb 文件拷贝到DRAM 中,地址分别为 0X80800000 和 0X83000000,最后使用 bootz 启动,命令如下:

 (2)bootm命令

bootm 和 bootz 功能类似,但是bootm 用于启动 uImage 镜像文件。如果不使用设备树的话启动 Linux 内核的命令如下:

bootm addr

addr 是 uImage 镜像在DRAM 中的首地址。如果要使用设备树,那么 bootm 命令和 bootz 一样,命令格式如下:

bootm [addr [initrd[:size]] [fdt]]

其中 addr 是 uImage 在 DRAM 中的首地址,initrd 是 initrd 的地址,fdt 是设备树(.dtb)文件在 DRAM 中的首地址,如果 initrd 为空的话,同样是用“-”来替代。

(3)boot命令

boot 命令也是用来启动Linux 系统的,只是 boot 会读取环境变量 bootcmd 来启动 Linux 系统,bootcmd 是一个很重要的环境变量!其名字分为“boot”和“cmd”,也就是“引导”和“命令”,说明这个环境变量保存着引导命令,其实就是启动的命令集合,具体的引导命令内容是可以修改的。

比如我们要想使用 tftp 命令从网络启动 Linux 那么就可以设置 bootcmd 为“tftp 80800000   zImage;   tftp   83000000   imx6ull-14x14-emmc-4.3-800x480-c.dtb;   bootz   80800000  - 83000000”,然后使用 saveenv 将 bootcmd 保存起来。然后直接输入 boot 命令即可从网络启动Linux 系统,命令如下

setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-4.3-800x480-c.dtb; bootz 80800000 - 83000000'
saveenv
boot

前面说过 uboot 倒计时结束以后就会启动Linux 系统,其实就是执行的 bootcmd 中的启动命令。只要不修改 bootcmd 中的内容,以后每次开机uboot 倒计时结束以后都会使用 tftp 命令从网络下载zImage 和 imx6ull-14x14-emmc-4.3-800x480-c.dtb,然后启动 Linux。

如果想从 EMMC 启动那就设置 bootcmd 为“fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14-emmc-4.3-800x480-c.dtb; bootz 80800000 - 83000000”,然后使用 boot命令启动即可,命令如下

如果不修改 bootcmd 的话,每次开机 uboot 倒计时结束以后都会自动从 EMMC 里面读取zImage 和 imx6ull-14x14-emmc-4.3-800x480-c.dtb,然后启动 Linux。

在启动 Linux 内核的时候可能会遇到如下错误

Kernel panic not Syncing: VFS: Unable to mount root fs on unknown-block(0,0)

这个错误的原因是 linux 内核没有找到根文件系统,这个很正常,因为没有设置 uboot 的bootargs 环境变量,配置了根文件系统就没有了

 4.9 其他常用操作命令

uboot 中还有其他一些常用的命令,比如reset、go、run 和 mtest 等。

(1)reset命令

(2) go命令

go 命令用于跳到指定的地址处执行应用,命令格式如下

go addr [arg ...]

addr 是应用在DRAM 中的首地址,我们可以编译一下裸机例程的实验 13_printf,然后将编译出来的 printf.bin 拷贝到 Ubuntu 中的 tftpboot 文件夹里面,注意,这里要拷贝 printf.bin 文件, 不需要在前面添加 IVT 信息,因为 uboot 已经初始化好了 DDR 了。使用 tftp 命令将 printf.bin 下载到开发板 DRAM 的 0X87800000 地址处,因为裸机例程的链接首地址就是 0X87800000, 最后使用 go 命令启动 printf.bin 这个应用,命令如下:

 从上图 可以看出,通过go命令我们就可以在uboot 中运行裸机例程。

(3)run命令

run 命令用于运行环境变量中定义的命令,比如可以通过“run bootcmd”来运行 bootcmd 中的启动命令,但是 run 命令最大的作用在于运行我们自定义的环境变量。在后面调试 Linux 系统的时候常常要在网络启动和 EMMC/NAND 启动之间来回切换,而 bootcmd 只能保存一种启动方式,如果要换另外一种启动方式的话就得重写 bootcmd,会很麻烦。这里我们就可以通过自定义环境变量来实现不同的启动方式,比如定义环境变量 mybootemmc 表示从 emmc 启动, 定义 mybootnet 表示从网络启动,定义 mybootnand 表示从 NAND 启动。如果要切换启动方式的话只需要运行“run mybootxxx(xxx 为 emmc、net 或 nand)”即可。

创建环境变量 mybootemmc、mybootnet 和 mybootnand,命令如下:

setenv mybootemmc 'fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-
14x14-emmc-4.3-800x480-c.dtb;bootz 80800000 - 83000000'
setenv mybootnand 'nand read 80800000 4000000 800000;nand read 83000000 6000000
100000;bootz 80800000 - 83000000'
setenv mybootnet 'tftp 80800000 zImage; tftp 83000000imx6ull-14x14-emmc-4.3-800x480-c.dtb; bootz 80800000 - 83000000'
saveenv

创建环境变量成功以后就可以使用 run 命令来运行 mybootemmc、mybootnet 或 mybootnand来实现不同的启动:

run mybootemmc
run mytoobnand
run mybootnet
(4)mtest命令

mtest 命令是一个简单的内存读写测试命令,可以用来测试自己开发板上的 DDR,命令格式如下:

mtest [start [end [pattern [iterations]]]]

start 是要测试的DRAM 开始地址,end 是结束地址,比如我们测试 0X80000000~0X80001000这段内存,输入“mtest 80000000 80001000”

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值