LV09-03-linux-01-内核加载

本文主要是linux——内核加载的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
Linux开发板 华清远见 底板: FS4412_DEV_V5 核心板: FS4412 V2
u-boot 2013.01
点击查看本文参考资料
参考方向 参考原文
------
点击查看相关文件下载
文件下载链接
exynos4412-fs4412.rar设备树文件
ramdisk.rarlinux镜像
roofs.rar根文件系统(通过nfs共享给开发板的时候用)
ramdisk.rar根文件系统镜像

一、所需文件下载

开篇我放了自己在蓝奏云存储的几个文件,我们可以下载下来并解压,然后我们会的到下边几个文件:

image-20220816165850235

这些文件都存放在windowsubuntu共享目录下,在ubuntu中共享文件路径为:

1
/mnt/hgfs/Sharedfiles/test/linux

二、加载方式与准备工作

1. 加载方式简介

我们可以有以下几种方式来加载linux内核和根文件系统:

方式一 tftp加载linux内核,tftp加载rootfs根文件系统
方式二 eMMC加载linux内核,eMMC加载rootfs根文件系统
方式三 tftp加载linux内核,nfs加载rootfs根文件系统

后边将详细介绍这三种方式。

2. 加载前的准备

2.1 网络设置

我们首先要设置开发板中的服务器IPubuntu服务器IP,在SecureCRT终端中执行以下命令:

1
2
3
4
5
6
7
8
fs4412 # setenv ipaddr 192.168.10.102
fs4412 # setenv ethaddr 11:22:33:44:55:66
fs4412 # setenv gatewayip 192.168.10.1
fs4412 # setenv netmask 255.255.255.0
fs4412 # setenv serverip 192.168.10.101

# 最后再保存一下环境变量到 mmc
fs4412 # saveenv

2.2 tftp

首先我们要保证自己已经安装了tftp,并且可以正常使用,我的ubuntu服务器iptftp目录如下:

1
192.168.10.101:/home/hk/3tftp

由于我已经在开发板中设置了serverip192.168.10.101,且所有fs4412linux内核加载和根文件系统加载中所需的文件都放在下面的路径中:

1
/home/hk/3tftp/fs4412

故后边在开发板的交互界面可以直接通过下边类似命令下载文件:

1
fs4412 # tftp 40008000 /fs4412/clear.bin

2.3 nfs

后边会用到nfs来挂载根文件系统,所以我们需要确保我们的ubuntu服务器已经设置好了nfs共享文件夹,我设置的文件夹为:

1
/home/hk/4nfs

2.4 文件准备

之前我们已经将相关文件下载并解压到了ubuntuwindows下的共享目录中,接下来就是将相关文件拷贝到3tftp/fs4412或者nfd路径下了,相关拷贝命令如下:

  • ~/3tftp/fs4412/路径下需要有的文件
1
2
3
hk@vm:~$ cp /mnt/hgfs/Sharedfiles/test/linux/exynos4412-fs4412.dtb ~/3tftp/fs4412/
hk@vm:~$ cp /mnt/hgfs/Sharedfiles/test/linux/ramdisk.img ~/3tftp/fs4412/
hk@vm:~$ cp /mnt/hgfs/Sharedfiles/test/linux/uImage ~/3tftp/fs4412/
  • ~/nfs路径下需要有的文件(方式三会使用)
1
hk@vm:~$ cp /mnt/hgfs/Sharedfiles/test/linux/roofs/rootfs.tar.bz2 ~/nfs/

这个文件复制完毕之后我们还需要进行解压,我们可以在终端执行以下命令:

1
2
3
hk@vm:~$ cd ~/nfs/
hk@vm:~/nfs$ tar xvf rootfs.tar.bz2
hk@vm:~/nfs$ rm rootfs.tar.bz2

三、加载方式一

方式一就是我们通过tftp来加载linux系统内核和rootfs根文件系统。

1. 修改bootcmd

我们修改一下uboot的启动参数,让其在启动后读秒结束直接从ubuntu下载相关文件并启动linux内核。我们在secureCRT终端执行以下命令:

1
2
3
4
5
6
fs4412 # setenv bootcmd tftp 0x41000000 /fs4412/uImage\;tftp 0x42000000 /fs4412/exynos4412-fs4412.dtb\;tftp 0x43000000 /fs4412/ramdisk.img\;bootm 0x41000000 0x43000000 0x42000000

# 然后保存一下环境变量到 eMMC
fs4412 # saveenv
Saving Environment to MMC...
Writing to MMC(0)... .done

然后我们打印一下这个环境变量的值,检查一下:

1
2
fs4412 # printenv bootcmd
bootcmd=tftp 0x41000000 /fs4412/uImage;tftp 0x42000000 /fs4412/exynos4412-fs4412.dtb;tftp 0x43000000 /fs4412/ramdisk.img;bootm 0x41000000 0x43000000 0x42000000

【注意】

(1)多条命令之间用\;分隔开。

(2)bootm参数顺序为内核的下载地址、根文件系统的下载地址、设备树的下载地址。

2. 修改bootargs

我们还需要修改一下传给linux的参数信息,也就是修改一下bootargs环境变量的值。我们在secureCRT终端执行以下命令:

1
2
3
4
5
6
fs4412 # setenv bootargs root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.10.102

# 然后保存一下环境变量到 eMMC
fs4412 # saveenv
Saving Environment to MMC...
Writing to MMC(0)... .done

然后我们打印一下这个环境变量的值,检查一下:

1
2
fs4412 # printenv bootargs
bootargs=root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.10.102

【注意】

(1)nfsroot=192.168.10.101后边那个IPubuntu服务器的IPip=192.168.10.102后边的这个IP为开发板自己的IP,需要确保这两个IP处于同一网段。

(2)该种加载方式的根文件系统并非来自于nfs共享目录,而是来自于根文件系统镜像。

3. 重启开发板

3.1 uImage文件加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/uImage'.
Load address: 0x41000000
Loading: T #################################################################
#################################################################
#################################################################
###########
378.9 KiB/s
done
Bytes transferred = 3019120 (2e1170 hex)

3.2 exynos4412-fs4412.dtb文件加载

1
2
3
4
5
6
7
8
9
10
11
12
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/exynos4412-fs4412.dtb'.
Load address: 0x42000000
Loading: T ###
5.9 KiB/s
done
Bytes transferred = 34358 (8636 hex)

3.3 ramdisk.img文件加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/ramdisk.img'.
Load address: 0x43000000
Loading: T #################################################################
#################################################################
############################################
338.9 KiB/s
done
Bytes transferred = 2544147 (26d213 hex)

3.4 三个文件检测信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
## Booting kernel from Legacy Image at 41000000 ...
Image Name: Linux-3.14.0
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3019056 Bytes = 2.9 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum ... OK
## Loading init Ramdisk from Legacy Image at 43000000 ...
Image Name: ramdisk
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 2544083 Bytes = 2.4 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 42000000
Booting using the fdt blob at 0x42000000
Loading Kernel Image ... OK
OK
Loading Ramdisk to 4fd92000, end 4ffff1d3 ... OK
Loading Device Tree to 4fd86000, end 4fd91635 ... OK

3.5 启动内核

1
Starting kernel ...

当我们看到这个信息的时候,说明后边的操作将会启动linux内核。

3.6 挂载根文件系统

在内核安装完毕之后,会进行根文件系统挂载,挂载完成将会有以下信息提示:

1
[    2.145000] VFS: Mounted root (ext2 filesystem) on device 1:0.

4. 启动成功

当我们的开发板加载linux内核并启动成功的时候,我们可以运行一个ls命令来检测一下:

image-20220817164442440

四、加载方式二

通过方式一我们虽然可以加载Linux内核和根文件系统并正常运行,但方式一我们是把内核镜像、设备树、根文件系统镜像都放到了tftp服务器上,然后开发板上电之后再通过tftp去下载这些文件到开发板的内存中运行;但在实际我们不可能每次开机都通过网络去服务器上下载这些镜像,所以以下步骤我们就将这些镜像安装到开发板上的eMMC 中,然后从EMMC启动内核。

下边我们就来使用加载方式二,通过eMMC来加载linux内核和rootfs根文件系统。

1. 相关文件下载

1.1 linux镜像

  • 下载内核镜像到内存中
1
fs4412 # tftp 0x41000000 /fs4412/uImage

下载完成会有以下提示信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/uImage'.
Load address: 0x41000000
Loading: T #################################################################
#################################################################
#################################################################
###########
380.9 KiB/s
done
Bytes transferred = 3019120 (2e1170 hex)
  • 将内核镜像写入到eMMC中指定的扇区

uImage大小为2.9M,也就是2.9 * 1024 * 1024 = 3040870.4字节,写入到eMMC的时候,每个块,或者说扇区的大小为512字节,所以uImage一共会占3040870.4 / 512 = 5939.2个扇区,大概就是5940个扇区,换算为十六进制为0x1734,所以使用的扇区数量我们可以设置为0x2000

1
fs4412 # mmc write 0 0x41000000 0x800 0x2000

写入成功会有以下提示信息:

1
2
MMC write: dev # 0, block # 2048, count 8192. 8192 blocks write finish
8192 blocks written: OK

1.2 设备树

  • 下载设备树到内存中
1
fs4412 # tftp 0x41000000 /fs4412/exynos4412-fs4412.dtb

下载完成会有以下提示信息:

1
2
3
4
5
6
7
8
9
10
11
12
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/exynos4412-fs4412.dtb'.
Load address: 0x41000000
Loading: T ###
5.9 KiB/s
done
Bytes transferred = 34358 (8636 hex)
  • 将设备树写入到eMMC中指定的扇区

exynos4412-fs4412.dtb大小为34K,也就是34 * 1024 = 34816字节,写入到eMMC的时候,每个块,或者说扇区的大小为512字节,所以exynos4412-fs4412.dtb一共会占34816 / 512 = 68个扇区,换算为十六进制为0x44,所以使用的扇区数量我们可以设置为0x800

1
fs4412 # mmc write 0 0x41000000 0x2800 0x800

写入成功会有以下提示信息:

1
2
MMC write: dev # 0, block # 10240, count 2048. 2048 blocks write finish
2048 blocks written: OK

1.3 根文件系统镜像

  • 下载根文件系统镜像到内存中
1
fs4412 # tftp 0x41000000 /fs4412/ramdisk.img

下载完成会有以下提示信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/ramdisk.img'.
Load address: 0x41000000
Loading: T #################################################################
#################################################################
############################################
335.9 KiB/s
done
Bytes transferred = 2544147 (26d213 hex)
  • 将根文件系统镜像写入到eMMC中指定的扇区

ramdisk.img大小为2.5M,也就是2.5 * 1024 * 1024 = 2621440字节,写入到eMMC的时候,每个块,或者说扇区的大小为512字节,所以ramdisk.img一共会占2621440 / 512 = 5120个扇区,换算为十六进制为0x1400,所以使用的扇区数量我们可以设置为0x2000

1
fs4412 # mmc write 0 0x41000000 0x3000 0x2000

写入成功会有以下提示信息:

1
2
MMC write: dev # 0, block # 12288, count 8192. 8192 blocks write finish
8192 blocks written: OK

2. 修改bootcmd

我们在secureCRT终端执行以下命令:

1
2
3
4
5
6
fs4412 # setenv bootcmd mmc read 0 0x41000000 0x800 0x2000\;mmc read 0 0x42000000 0x2800 0x800\;mmc read 0 0x43000000 0x3000 0x2000\;bootm 0x41000000 0x43000000 0x42000000

# 然后保存一下环境变量到 eMMC
fs4412 # saveenv
Saving Environment to MMC...
Writing to MMC(0)... .done
点击查看可能出现的问题及解决方式

我们按下enter按键确认的时候可能会有以下提示信息:

1
2
3
4
5
6
7
setenv - set environment variables

Usage:
setenv [-f] name value ...
- [forcibly] set environment variable 'name' to 'value ...'
setenv [-f] name
- [forcibly] delete environment variable 'name'

这个时候我们可以这样解决,将命令用' '包裹:

1
fs4412 # setenv bootcmd 'mmc read 0 0x41000000 0x800 0x2000\;mmc read 0 0x42000000 0x2800 0x800\;mmc read 0 0x43000000 0x3000 0x2000\;bootm 0x41000000 0x43000000 0x42000000'

然后我们打印一下这个环境变量的值,检查一下:

1
2
fs4412 # printenv bootcmd
bootcmd=mmc read 0 0x41000000 0x800 0x2000;mmc read 0 0x42000000 0x2800 0x800;mmc read 0 0x43000000 0x3000 0x2000;bootm 0x41000000 0x43000000 0x42000000

【注意】

(1)多条命令之间用\;分隔开。

(2)bootm参数顺序为内核的下载地址、根文件系统的下载地址、设备树的下载地址。

3. 修改bootargs

我们还需要修改一下传给linux的参数信息,也就是修改一下bootargs环境变量的值。我们在secureCRT终端执行以下命令:

1
2
3
4
5
6
fs4412 # setenv bootargs root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.10.102

# 然后保存一下环境变量到 eMMC
fs4412 # saveenv
Saving Environment to MMC...
Writing to MMC(0)... .done

然后我们打印一下这个环境变量的值,检查一下:

1
2
fs4412 # printenv bootargs
bootargs=root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.10.102

【注意】

(1)nfsroot=192.168.10.101后边那个IPubuntu服务器的IPip=192.168.10.102后边的这个IP为开发板自己的IP,需要确保这两个IP处于同一网段。

(2)该种加载方式的根文件系统并非来自于nfs共享目录,而是来自于根文件系统镜像。

4. 重启开发板

4.1 uImage文件加载

1
MMC read: dev # 0, block # 2048, count 8192 ...8192 blocks read: OK

4.2 exynos4412-fs4412.dtb文件加载

1
MMC read: dev # 0, block # 10240, count 2048 ...2048 blocks read: OK

4.3 ramdisk.img文件加载

1
MMC read: dev # 0, block # 12288, count 8192 ...8192 blocks read: OK

4.4 三个文件检测信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
## Booting kernel from Legacy Image at 41000000 ...
Image Name: Linux-3.14.0
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3019056 Bytes = 2.9 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum ... OK
## Loading init Ramdisk from Legacy Image at 43000000 ...
Image Name: ramdisk
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 2544083 Bytes = 2.4 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 42000000
Booting using the fdt blob at 0x42000000
Loading Kernel Image ... OK
OK
Loading Ramdisk to 4fd92000, end 4ffff1d3 ... OK
Loading Device Tree to 4fd86000, end 4fd91635 ... OK

4.5 启动内核

1
Starting kernel ...

当我们看到这个信息的时候,说明后边的操作将会启动linux内核。

4.6 挂载根文件系统

在内核安装完毕之后,会进行根文件系统挂载,挂载完成将会有以下信息提示:

1
[    2.205000] VFS: Mounted root (ext2 filesystem) on device 1:0.

5. 启动成功

当我们的开发板加载linux内核并启动成功的时候,我们可以运行一个ls命令来检测一下:

image-20220817170501606

五、加载方式三

在进行开发的过程中会经常修改内核和设备树的源码,也会经常向根文件系统中添加一些驱动或应用程序,这样每次修改之后我们都要重新将内核或根文件系统安装到eMMC中,步骤会比较繁琐,开发效率也比较低,所以在开发阶段我们经常使用的方式是通过tftp
载内核和设备树再通过nfs挂载根文件系统,这样步骤简单,效率也比较高,待开发完成之后在安装到eMMC中。

下边我们就来使用加载方式三,通过tftp来加载linux内核,通过nfs加载rootfs根文件系统。该方式会用到nfs,开发板中在linux内核安装完成后,是已经安装了nfs的,所以我们只需要保证ubuntu安装了nfs,并设置了可访问的共享目录即可。

1. 修改bootcmd

我们在secureCRT终端执行以下命令:

1
2
3
4
5
6
fs4412 # setenv bootcmd tftp 0x41000000 /fs4412/uImage\;tftp 0x42000000 /fs4412/exynos4412-fs4412.dtb\;bootm 0x41000000 - 0x42000000

# 然后保存一下环境变量到 eMMC
fs4412 # saveenv
Saving Environment to MMC...
Writing to MMC(0)... .done

然后我们打印一下这个环境变量的值,检查一下:

1
2
fs4412 # printenv bootcmd
bootcmd=tftp 0x41000000 /fs4412/uImage;tftp 0x42000000 /fs4412/exynos4412-fs4412.dtb;bootm 0x41000000 - 0x42000000

【注意】

(1)多条命令之间用\;分隔开。

(2)bootm参数顺序为内核的下载地址、根文件系统的下载地址、设备树的下载地址。

2. 修改bootargs

我们还需要修改一下传给linux的参数信息,也就是修改一下bootargs环境变量的值。我们在secureCRT终端执行以下命令:

1
2
3
4
5
6
fs4412 # setenv bootargs root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.10.102

# 然后保存一下环境变量到 eMMC
fs4412 # saveenv
Saving Environment to MMC...
Writing to MMC(0)... .done

然后我们打印一下这个环境变量的值,检查一下:

1
2
fs4412 # printenv bootargs
bootargs=root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.10.102

【注意】

(1)nfsroot=192.168.10.101后边那个IPubuntu服务器的IPip=192.168.10.102后边的这个IP为开发板自己的IP,需要确保这两个IP处于同一网段。

(2)该种加载方式的根文件系统来自于nfs共享目录,所以我们可以在ubuntu服务器上对根文件系统进行操作。

3. 重启开发板

3.1 uImage文件加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/uImage'.
Load address: 0x41000000
Loading: T #################################################################
#################################################################
#################################################################
###########
378.9 KiB/s
done
Bytes transferred = 3019120 (2e1170 hex)

3.2 exynos4412-fs4412.dtb文件加载

1
2
3
4
5
6
7
8
9
10
11
12
dm9000 i/o: 0x5000000, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 11:22:33:44:55:66
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.10.101; our IP address is 192.168.10.102
Filename '/fs4412/exynos4412-fs4412.dtb'.
Load address: 0x42000000
Loading: T ###
5.9 KiB/s
done
Bytes transferred = 34358 (8636 hex)

3.3 两个文件检测信息

1
2
3
4
5
6
7
8
9
10
11
12
## Booting kernel from Legacy Image at 41000000 ...
Image Name: Linux-3.14.0
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3019056 Bytes = 2.9 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum ... OK
## Flattened Device Tree blob at 42000000
Booting using the fdt blob at 0x42000000
Loading Kernel Image ... OK
OK
Loading Device Tree to 4fff4000, end 4ffff635 ... OK

3.4 启动内核

1
Starting kernel ...

当我们看到这个信息的时候,说明后边的操作将会启动linux内核。

3.5 挂载根文件系统

在内核安装完毕之后,会进行根文件系统挂载,挂载完成将会有以下信息提示:

1
2
3
[    2.855000] VFS: Mounted root (nfs filesystem) on device 0:10.
[ 2.860000] devtmpfs: mounted
[ 2.865000] Freeing unused kernel memory: 228K (c052d000 - c0566000)

注意这里很容易卡死,nfs共享目录的设置一定要保证其他机器可以正常访问,另外需要注意这里使用的uboo2013版本只支持nfs2,而高版本的ubuntu已经不支持这个版本了,有的资料说在一个文件中配置一下就行,但是我好像没有成功,所以只能换了ubuntu的版本,更换了16.04版本后就没有问题了,后边知道高版本的怎么处理了再在这里补充吧。

4. 启动成功

当我们的开发板加载linux内核并启动成功的时候,我们可以运行一个ls命令来检测一下:

image-20220818130030409