Bootstrap

linux系统移植

前言

主要介绍linux系统的移植,有待完善


一、uboot简介

1.1 uboot命令

①环境变量操作命令:
(1)命令 setenv 用于设置或者修改环境变量的值
(2)命令 saveenv 用于保存修改后的环境变量
②网络操作命令
(1)ping验证是否可以与主机通信
(2)dhcp 用于从路由器获取 IP 地址
(3)通过 nfs 在计算机之间通过网络来分享资源,如:

nfs 80800000 192.168.1.253:/home/sky/linux/nfs/zImage

(4)通过tftp在计算机之间通过网络来分享资源,如:

tftp 80800000 zImage

③ EMMC 和 SD 卡操作命令
在这里插入图片描述

④BOOT 操作命令
(1)bootz 命令用于启动 zImage 镜像文件
(2)bootm 用于启动 uImage 镜像文件
(3) boot 会读取环境变量 bootcmd 来启动 Linux 系统,如:

setenv bootcmd ‘tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000’
saveenv
boot

1.2 make 命令流程

在这里插入图片描述

1.3 bootz 命令执行过程

在这里插入图片描述

二、uboot移植

2.1 uboot编译环境搭建

①在 Ubuntu 中安装 ncurses 库,生成基于文本的图形界面

sudo apt-get install build-essential
sudo apt-get install libncurses5-dev

②在 Ubuntu 上搭建 TFTP 服务器(作用类似nfs)
(1)安装服务

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

(2)创建文件夹

mkdir /home/zuozhongkai/linux/tftpboot
chmod 777 /home/zuozhongkai/linux/tftpboot

(3)配置tftp

sudo vi /etc/xinetd.d/tftp #输入:

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

sudo service tftpd-hpa start(启动 tftp 服务)

(4)修改预设值

sudo vi /etc/default/tftpd-hpa #输入:

#/etc/default/tftpd-hpa
TFTP_USERNAME=“tftp”
TFTP_DIRECTORY=“/home/sky/linux/tftpboot”
TFTP_ADDRESS=“:69”
TFTP_OPTIONS=“-1 -c -s”

sudo service tftpd-hpa restart(重启 tftp 服务器)

(5)赋文件夹权限

cd /home/sky/linux/tftpboot/
chmod 777 zImage

2.2 创建默认配置文件

在configs 目录下,复制 mx6ull_14x14_evk_emmc_defconfig,

cp mx6ull_14x14_evk_emmc_defconfig mx6ull_alientek_emmc_defconfig

并修改内容为:

CONFIG_SYS_EXTRA_OPTIONS=“IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK”
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
CONFIG_CMD_GPIO=y

2.3 添加开发板对应的头文件

在目录 include/configs 下添加 I.MX6ULL-ALPHA开发板对应的头文件 , 复 制include/configs/mx6ullevk.h,cp mx6ullevk.h mx6ull_alientek_emmc.h并修改宏定义

#ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H

2.4 添加开发板对应的板级文件夹

在 board/freescale 目录下,复制 mx6ullevk文件夹将其重命名为 mx6ull_alientek_emmc,命令为:

cp mx6ullevk/ -r mx6ull_alientek_emmc

① 将 其 中 的 mx6ullevk.c 文 件 重 命 名 为mx6ull_alientek_emmc.c:
mv mx6ullevk.c mx6ull_alientek_emmc.c
②修改 mx6ull_alientek_emmc 目录下的 Makefile 文件,第 6 行的 obj-y,改为 mx6ull_alientek_emmc.o,这样才会编译 mx6ull_alientek_emmc.c这个文件
③修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件,将PLUGIN改成:

PLUGIN board/freescale/mx6ull_alientek_emmc /plugin.bin 0x00907000

④修改 mx6ull_alientek_emmc 目录下的 Kconfig 文件,改为

if TARGET_MX6ULL_ALIENTEK_EMMC
config SYS_BOARD
	default "mx6ull_alientek_emmc"
config SYS_VENDOR
	default "freescale"
config SYS_SOC
	default "mx6"
config SYS_CONFIG_NAME
	default "mx6ull_alientek_emmc"
endif

⑤修改 mx6ull_alientek_emmc 目录下的 MAINTAINERS 文件,改为:

MX6ULL_ALIENTEK_EMMC BOARD
M:	Peng Fan <peng.fan@nxp.com>
S:	Maintained
F:	board/freescale/mx6ull_alientek_emmc/
F:	include/configs/mx6ull_alientek_emmc.h

2.5 修改 U-Boot 图形界面配置文件

修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件),这样就将自己的开发板名称添加进来,在207行添加:

config TARGET_MX6ULL_ALIENTEK_EMMC
	bool "Support mx6ull_alientek_emmc"
	select MX6ULL
	select DM
	select DM_THERMAL

在最后endif前添加:

source "board/freescale/mx6ull_alientek_emmc/Kconfig"

2.6 LCD 驱动修改

①LCD 所使用的 GPIO,查看 uboot 中 LCD 的 IO 配置是否正确。
②LCD 背光引脚 GPIO 的配置。
③LCD 配置参数是否正确
(1)打开文件 mx6ull_alientek_emmc.c,找到类型为 display_info_t,这个结构体是 LCD信息结构体,display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h 中,pixfmt 是像素格式,如果是 888 的话就是 24 位,一般使用 RGB888。像素时钟31.5MHz,所以 pixclock=(1/31500000)*10^12=31,746,所以将其修改为

struct display_info_t const displays[] = {{
	.bus = MX6UL_LCDIF1_BASE_ADDR,
	.addr = 0,
	.pixfmt = 24,
	.detect = NULL,
	.enable	= do_enable_parallel_lcd,
	.mode	= {
		.name			= "TFT7016",
		.xres           = 1024,
		.yres           = 600,
		.pixclock       = 19531,
		.left_margin    = 140,			//HBPD
		.right_margin   = 160,			//HFPD
		.upper_margin   = 20,			//VBPD
		.lower_margin   = 12,			//VFBD
		.hsync_len      = 20,			//HSPW
		.vsync_len      = 3,			//VSPW
		.sync           = 0,
		.vmode          = FB_VMODE_NONINTERLACED
} } };

(2)在mx6ull_alientek_emmc.h将panel=TFT43AB改成panel=TFT7016

2.7 网络驱动修改

①修改内容:
(1)ENET1 、ENET2复位引脚初始化。
(2)LAN8720A 的器件 ID(即PHY芯片地址)。
(3)LAN8720 驱动
② PHY 芯片器件地址,打开 mx6ull_alientek_emmc.h
(1)335行修改 ENET1 网络 PHY 的地址

#define CONFIG_FEC_MXC_PHYADDR 0x0

(2)339行修改 ENET2 网络 PHY 的地址

#define CONFIG_FEC_MXC_PHYADDR 0x1

(3)345行使能 SMSC 公司的 PHY 驱动

#define CONFIG_PHY_SMSC

③删除 uboot 中 74LV595 的驱动代码,在 mx6ull_alientek_emmc.c中
(1)删除 uboot 中 74LV595 的复位相关GPIO

#define IOX_SDI IMX_GPIO_NR(5, 10)
#define IOX_STCP IMX_GPIO_NR(5, 7)
#define IOX_SHCP IMX_GPIO_NR(5, 11)
#define IOX_OE IMX_GPIO_NR(5, 8)

并将其改为ENET1 、ENET2复位引脚:

#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)

(2)删除74LV595 的 IO 配置参数结构体iomux_v3_cfg_t const iox_pads[],初始化函数 iox74lv_init,和74LV595 的 IO 输出函数iox74lv_set,并且删除板子初始化函数board_init里的下面两行:

imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));
iox74lv_init();

④添加ENET1 和 ENET2网络复位引脚驱动,在 mx6ull_alientek_emmc.c 中
(1)对 ENET1 和 ENET2 这两个网口的 IO 配置参数,在结构体数组 fec1_pads 里添加:

MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)

在fec2_pads 里添加:

MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),

(2)函数 setup_iomux_fec 就是根据 fec1_pads 和 fec2_pads 这两个网络 IO 配置数组来初始化I.MX6ULL 的网络 IO,将这两个 IO 设置为输出并且硬件复位一下 LAN8720A:

static void setup_iomux_fec(int fec_id)
{
	if (fec_id == 0)
	{
		imx_iomux_v3_setup_multiple_pads(fec1_pads,
						 ARRAY_SIZE(fec1_pads));
		gpio_direction_output(ENET1_RESET, 1);
		gpio_set_value(ENET1_RESET, 0);
		mdelay(100);
		gpio_set_value(ENET1_RESET, 1);
	}
	else
	{
		imx_iomux_v3_setup_multiple_pads(fec2_pads,
						 ARRAY_SIZE(fec2_pads));
		gpio_direction_output(ENET2_RESET, 1);
		gpio_set_value(ENET2_RESET, 0);
		mdelay(100);
		gpio_set_value(ENET2_RESET, 1);
	}
}

⑤修改 drivers/net/phy/phy.c 文件中的函数 genphy_update_link,此函数用于更新 PHY 的连接状态和速度

#ifdef CONFIG_PHY_SMSC
    static int lan8720_flag = 0;
    int bmcr_reg = 0;
    if (lan8720_flag == 0) {
        bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
        phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
        while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) {
            udelay(100);
        }
        phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);
        lan8720_flag = 1;
    } 
#endif

2.8 修改uboot启动板子名字

打开文件 mx6ull_alientek_emmc.c,找到函数checkboard

int checkboard(void)
{
    if (is_mx6ull_9x9_evk())
        puts("Board: MX6ULL 9x9 EVK\n");
    else
        puts("Board: MX6ULL ALIENTEK EMMC\n");

    return 0;
}

2.9 bootcmd 和 bootargs 环境变量

文 件 mx6ull_alientek_emmc.h 中的宏CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值
①bootcmd 保存着 uboot 默认命令,uboot 倒计时结束以后就会执行 bootcmd 中的命令,这些命令一般都是用来启动 Linux 内核的,我们可以在mx6ull_alientek_emmc.h 文件中通过设置宏 CONFIG_BOOTCOMMAND 来设置 bootcmd 的默认值,如:

#define CONFIG_BOOTCOMMAND \
	"mmc dev 1;" \
	"fatload mmc 1:1 0x80800000 zImage;" \
	"fatload mmc 1:1 0x83000000 imx6ull-alientek-emmc.dtb;" \
	"bootz 0x80800000 - 0x83000000;"

②bootargs 保存着 uboot 传递给 Linux 内核的参数,bootargs 环境变量是由 mmcargs 设置:

mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}

2.10 uboot 启动 Linux 测试

①编译uboot
(1)在uboot根目录下编写mx6ull_alientek_emmc.sh 脚本,内容如下:

#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig #打开图形化界面
make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

(2)或者在顶层Makefile里249行下面添加,来减少命令

ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-

(3)编译好后查 看一下添加的mx6ull_alientek_emmc.h 这个头文件有没有引用,可以使用命令:

grep -nR "mx6ull_alientek_emmc.h"

(4)下载到SD卡:

chmod 777 imxdownload
./imxdownload u-boot.bin /dev/sdb

②在uboot里配置启动方式环境变量,并使用boot命令启动,复位后按回车键回uboot
(1)从 EMMC 启动 Linux 系统

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000  imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'
saveenv

(2)从网络启动 Linux 系统

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-4.3-800x480-c.dtb; bootz 80800000 - 83000000'
saveenv

③修改LCD环境变量:

setenv panel TFT7016
saveenv

④设置网络环境变量
在这里插入图片描述

setenv ipaddr 192.168.31.55
setenv ethaddr b8:ae:1d:01:00:00 
setenv gatewayip 192.168.31.1
setenv netmask 255.255.255.0 
setenv serverip 192.168.31.141 
saveenv

三、Linux 内核移植

3.1 添加开发板默认配置文件

将 arch/arm/configs 目 录 下 的 imx_v7_mfg_defconfig 重 新 复 制 一 份 , 命 名 为imx_alientek_emmc_defconfig,之后就可以使用make imx_alientek_emmc_defconfig配置

cp imx_v7_mfg_defconfig imx_alientek_emmc_defconfig

3.2 添加开发板对应的设备树文件

①进入目录 arch/arm/boot/dts 中,复制 imx6ull-14x14-evk.dts,然后将其重命名为 imx6ull-alientek-emmc.dts,.dts 是设备树源码文件,编译 Linux 的时候会将其编译为.dtb 文件

cp imx6ull-14x14-evk.dts imx6ull-alientek-emmc.dts

②修改文件arch/arm/boot/dts/Makefile ,找到“dtb-$(CONFIG_SOC_IMX6ULL)”配置项,在此配置项中加入“imx6ull-alientek-emmc.dtb”

3.3 CPU 主频修改

当前 CPU 支持 198MHz、396MHz、528Mhz 和 792MHz 四种频率切换,想让 CPU 一直工作在 792MHz
①配置 Linux 内核,将调频策略 scaling_governor选择为 performance
②修改imx_alientek_emmc_defconfig为:

#CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y

③过图形化界面配置 Linux 内核的 CPU 调频策略,输入“make menuconfig”

CPU Power Management
-> CPU Frequency scaling
-> Default CPUFreq governor

3.4 使能 8 线 EMMC 驱动

Linux 内核驱动里面 EMMC 默认是 4 线模式的,正点原子 EMMC 版本核心板上的 EMMC 采用的 8 位数据线,打开文件 imx6ull-alientek-emmc.dts,在linux根目录下使用命令“make dtbs”重新编译设备树

&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc2_8bit>;
	pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
	bus-width = <8>;
	non-removable;
	status = "okay";
};

3.5 修改网络驱动

打开设备树文件 imx6ullalientek-emmc.dts
①修改 LAN8720 的复位以及网络时钟引脚驱动
(1)在pinctrl_spi4: spi4grp里删掉初始化 SNVS_TAMPER7 和 SNVS_TAMPER8 引脚

MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000

(2)在spi4里删掉GPIO5_IO07 和 GPIO5_IO08 功能引脚,与 ENET1 和 ENET2 的复位引脚冲突:

pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
cs-gpios = <&gpio5 7 0>;

(3)在iomuxc_snvs函数里,imx6ul-evk{}中添加 ENET1 和 ENET2网络复位引脚信息:

pinctrl_enet1_reset: enet1resetgrp {
						fsl,pins = <
								MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07		0x10B0
						>;
                };
pinctrl_enet2_reset: enet2resetgrp {
						fsl,pins = <
						MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08		0x10B0
						>;
                };

(4)在pinctrl_enet1: enet1grp里修改一下 ENET1 和 ENET2 的网络时钟引脚配置

MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1	0x4001b009
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4001b009

②修改 fec1 和 fec2 节点的 pinctrl-0 属性找到名为“fec1”和“fec2”的这两个节点,修改其中的“pinctrl-0”属性值,修改 LAN8720A 的 PHY 地址0x0和0x1

&fec1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet1
				 &pinctrl_enet1_reset>;
	phy-mode = "rmii";
	phy-handle = <&ethphy0>;
phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
phy-reset-duration = <200>;
	status = "okay";
};
&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2
				 &pinctrl_enet2_reset>;
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
	phy-reset-duration = <200>;
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@0 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <0>;
		};

		ethphy1: ethernet-phy@1 {
			compatible = "ethernet-phy-ieee802.3-c22";
			reg = <1>;
		};
	};
};

④修改 fec_main.c 文件, 打开drivers/net/ethernet/freescale/fec_main.c,找到函数 fec_probe,在3452行添加代码:

/*设置 MX6UL_PAD_ENET1_TX_CLK 和 MX6UL_PAD_ENET2_TX_CLK这
两个 IO 的复用寄存器的 SION 位为 1。*/
void __iomem *IMX6U_ENET1_TX_CLK;
void __iomem *IMX6U_ENET2_TX_CLK;

IMX6U_ENET1_TX_CLK = ioremap(0X020E00DC, 4);
writel(0X14, IMX6U_ENET1_TX_CLK);

IMX6U_ENET2_TX_CLK = ioremap(0X020E00FC, 4);
writel(0X14, IMX6U_ENET2_TX_CLK);

⑤配置 Linux 内核,使能 LAN8720 驱动输入命令“make menuconfig”,打开图形化配置界面”

-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs

使能了 LAN8720A 的驱动,会在.config中存在如下代码:CONFIG_SMSC_PHY=y,当我们执行“make clean”清理工程以后.config 文件就会被删除掉,保存.config 文件方法:
(1)直接将.config 文件另存为 imx_alientek_emmc_defconfig,然后将其复制到 arch/arm/configs 目录下,替换以前的imx_alientek_emmc_defconfig
(2)通过图形界面保存配置文件

General setup->Save->输入“arch/arm/configs/imx_alientek_emmc_defconfig”->OK

⑥设置 LAN8720A 的 BMCR寄存器 bit15 为 1,所以在 Linux 中也需要对 LAN8720A 进行一次软复位,修改 LAN8720A 的驱动文件是 drivers/net/phy/smsc.c:
(1)添加头文件

#include <linux/of_gpio.h>
#include <linux/io.h>

(2)修改此文件中有个叫做 smsc_phy_reset 的函数

static int smsc_phy_reset(struct phy_device *phydev)
{
	int err, phy_reset;
	int msec = 1;
	struct device_node *np;

	if(phydev->addr == 0) /* FEC1  */ {
		np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000");
		if(np == NULL) {
			return -EINVAL;
		}
	}

	if(phydev->addr == 1) /* FEC2  */ {
		np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@020b4000");
		if(np == NULL) {
			return -EINVAL;
		}
	}

	err = of_property_read_u32(np, "phy-reset-duration", &msec);
	/* A sane reset duration should not be longer than 1s */
	if (!err && msec > 1000)
		msec = 1;
	phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
	if (!gpio_is_valid(phy_reset))
		return;

	gpio_direction_output(phy_reset, 0);
	gpio_set_value(phy_reset, 0);
	msleep(msec);
	gpio_set_value(phy_reset, 1);

	int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
	if (rc < 0)
		return rc;

	/* If the SMSC PHY is in power down mode, then set it
	 * in all capable mode before using it.
	 */
	if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {

		/* set "all capable" mode and reset the phy */
		rc |= MII_LAN83C185_MODE_ALL;
		phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
	}

	phy_write(phydev, MII_BMCR, BMCR_RESET);
	/* wait end of reset (max 500 ms) */
	int timeout = 50000;
	do {
		udelay(10);
		if (timeout-- == 0)
			return -1;
		rc = phy_read(phydev, MII_BMCR);
	} while (rc & BMCR_RESET);
	return 0;
}

3.6 Linux 内核编译

①Ubuntu下Linux 内核编译环境搭建(LZO 压缩库的压缩软件):

sudo apt-get install lzop

②解压缩Linux 内核:

tar -vxjf linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2

③修改顶层Makefile

ARCH		?= arm
CROSS_COMPILE	?= arm-linux-gnueabihf-

④编写编译脚本imx6ull_alientek_emmc.sh

#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig #图形化配置可删
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

⑤并将以下生成文件复制到tftpboot文件夹里
(1)Linux 内核镜像文件,在 arch/arm/boot/zImage。
(2)NXP 官方 I.MX6ULL EVK 开发板对应的设备树文件(使用make dtbs可以单独将.dts文件编译成.dtb文件),在 arch/arm/boot/dts/imx6ull-alientek-emmc.dtb
⑥在uboot 命令模式中使用 tftp 命令下载这两个文件并启动下载

tftp 80800000 zImage
tftp 83000000 imx6ull-alientek-emmc.dtb
bootz 80800000 - 83000000

⑦给两个网卡配置 IP 地址

ifconfig eth0 192.168.31.251
ifconfig eth1 192.168.31.252

四、根文件系统BusyBox的构建

4.1 修改 Makefile,添加编译器

CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
ARCH ?= arm

4.2 busybox 中文字符支持

①打开文件 busybox-1.29.0/libbb/printable_string.c,找到函数 printable_string
(1)/注释掉 if (c >= 0x7f)
break;
/
(2)将if (c < ’ ’ || c >= 0x7f) 改为if( c < ’ ')
②打开文件 busybox-1.29.0/libbb/unicode.c,找函数unicode_conv_to_printable2
(1)将d++ = (c >= ’ ’ && c < 0x7f) ? c : ‘?’;改为d++ = (c >= ’ ') ? c : ‘?’;
(2)将if (c < ’ ’ || c >= 0x7f)改为if(c < ’ ')

4.3 配置 busybox

①make defconfig(默认配置)和make menuconfig(图形配置)

(1)选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大,所以不要选中
Location:
-> Settings
-> Build static binary (no shared libs)
(2)-> Settings
-> vi-style line editing commands(设置*)
(3)-> Linux Module Utilities
-> Simplified modutils(取消勾选)
(4)使能 busybox 的 unicode 编码以支持中文
-> Settings
-> Support Unicode //选中
-> Check $ LC_ALL, $ LC_CTYPE and $ LANG environment variables //选中

②编译 busybox,并指定编译结果的存放目录

make #编译
make install CONFIG_PREFIX=/home/sky/linux/nfs/rootfs 

4.4 向根文件系统添加 lib 库

①向 的“/lib”目录添加库文件

mkdir lib dev proc mnt sys tmp root
cd lib/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp *so* *.a /home/sky/linux/nfs/rootfs/lib/ -d
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
cp *so* *.a /home/sky/linux/nfs/rootfs/lib/ -d

由于rootfs /lib里的ld-linuxarmhf.so.3 是快捷方式不能作为符号链接,故重新复制:

rm ld-linux-armhf.so.3
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp ld-linux-armhf.so.3 /home/sky/linux/nfs/rootfs/lib/

②向 rootfs 的“usr/lib”目录添加库文件

mkdir usr/lib
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
cp *so* *.a /home/sky/linux/nfs/rootfs/usr/lib/ -d

4.5 在 rootfs 中创建/etc配置文件

①创建/etc/init.d/rcS 文件,内容如下:

#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

②在 rootfs 中创建/etc/fstab ,fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区:

#<file system> <mount point> <type> <options> <dump> <pass> 
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0

③创建/etc/inittab 文件:
(1)格式:< id>:< runlevels>:< action>:< process>
< id>:每个指令的标识符,不能重复。但是对于 busybox 的 init 来说,有着特殊意义。对于 busybox 而言< id>用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控制 tty。
< runlevels>:对 busybox 来说此项完全没用,所以空着。
< process>:具体的动作,比如程序、脚本或命令等。
< action>:用于指定< process>可能用到的动作。busybox 支持的动作如表所示:
在这里插入图片描述

(2)参考 busybox 下的文件 examples/inittab创建一个/etc/inittab

#etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

4.6 根文件系统的功能测试

①重新设置 uboot里bootargs 环境变量的 root 值,使用boot命令启动linux内核

setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.31.141:/home/sky/linux/nfs/rootfs,proto=tcp rw ip=192.168.31.50:192.168.31.141:192.168.31.1:255.255.255.0::eth0:off' 
saveenv

②软件运行测试
将编译生成的可执行文件拷贝到 rootfs/drivers 目录下,终端输入如下命令:

cd /drivers 	#进入 drivers 目录
./hello & 	#执行 hello, &就是让 hello 在后台运行
ps		#查看软件PID
kill -9 pid	#关闭运行

③开机启动测试,在/etc/init.d/rcS 这个 shell 脚本添加:

#开机自启动
cd /drivers
./hello &
cd /

④外网连接测试,在 rootfs 中新建文件/etc/resolv.conf,然后在里面输入如下内容:

nameserver 114.114.114.114
nameserver 192.168.31.1

五、系统烧写

5.1 MfgTool 工作过程

①将 firmware 目录中的 uboot、linux kernel 和.dtb(设备树),然后通过 USB OTG 将这个文件下载到开发板的 DDR 中,目的就是在 DDR 中启动 Linux 系统,为后面的烧写做准备。
②经过第①步的操作,此时 Linux 系统已经运行起来了,系统运行起来以后就可以很方便的完成对 EMMC 的格式化、分区等操作。EMMC 分区建立好以后就可以从 files 中读取要烧写的 uboot、linux kernel、.dtb(设备树)和 rootfs 这 4 个文件,然后将其烧写到 EMMC 中,这个就是 MfgTool 的大概工作流程。

5.2 OS Firmware目录下文件简介

在L4.1.15_2.0.0-ga_mfg-tools/mfgtools-with-rootfs/mfgtools/Profiles/Linux/OS Firmware目录下:
①firmeare 文件夹(第一阶段)
在这里插入图片描述

②files 文件夹
在这里插入图片描述

③ucl2.xml 文件
files 和 firmware 目录下有众多的 uboot 和设备树,那么烧写的时候究竟选择哪一个呢?这个工作就是由 ucl2.xml 文件来完成的。ucl2.xml 首先会判断当前要向 I.MX 系列的哪个芯片烧写系统,确定了处理器以后就要确定向什么存储设备烧写系统,这个时候就要有请 mfgtool2-yocto-mx-evk-emmc.vbs 再次登场

5.3 系统烧写

①备好原材料u-boot.imx、 zImage 镜像文件和开发板对应的.dtb(设备树)imx6ull-alientek-emmc.dtb、根文件系统 rootfs压缩打包
②将上面四个文件重命名
在这里插入图片描述

③先将图中的 zImage、u-bootimx6ull14x14evk_emmc.imx 和 zImage-imx6ull-14x14-evk-emmc.dtb 这三个文件拷贝到 mfgtools-with-rootfs/mfgtools/Profiles/Linux/OS Firmware/firmware 目录中,替换掉原来的文件
④将4 个文件都拷贝到 mfgtools-with-rootfs/mfgtools/Profiles/Linux/OS Firmware/files目录中

5.4 网络开机自启动

设置ifconfig eth0 up,或者设置网卡 IP 地址的命令添加到/etc/init.d/rcS 文件中就行

#网络开机自启动设置
ifconfig eth0 up
#udhcpc -i eth0 
ifconfig eth0 192.168.31.251 netmask 255.255.255.0
route add default gw 192.168.31.1

5.5 烧写 NXP 官方系统

①连接好 USB,拨码开关拨到 USB 下载模式。
②弹出 TF 卡,然后按下开发板复位按键。
③双击“mfgtool2-yocto-mx-evk-emmc.vbs”,打开下载软件,如果出现“符合 HID 标准的供应商定义设备”等字样就说明下载软件已经准备就绪。点击“Start”按钮开发烧写 NXP 官方系统,好了之后Stop然后退出

5.6 解决 Linux 内核启动失败

①重新设置 bootcmd 环境变量值

setenv bootcmd 'mmc dev 1;fatload mmc 1:1 80800000 zImage;fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
saveenv

②修改 uboot 源码
打开 uboot 源码中的文件include/configs/mx6ull_alientek_emmc.h,在宏 CONFIG_EXTRA_ENV_SETTINGS 中findfdt 的值修改为:

 "findfdt="\
	"if test $fdt_file = undefined; then " \
	"setenv fdt_file imx6ull-alientek-emmc.dtb; " \
	"fi;\0" \
;