7 Linux 内核移植

一、编译 ST 的 Linux 系统

1. 压缩源码

  首先先下载 ST 官方源码,之前章节已经下载过了,直接输入以下命令:

cd linux/atk-mpl/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/

  然后压缩  linux-5.4.31.tar.xz  源码包压缩包:

tar -vxf linux-5.4.31.tar.xz

 

2. 给内核打补丁

输入以下命令:

cd linux-5.4.31/
for p in `ls -1 ../*.patch`; do patch -p1 < $p; done //打补丁

# ls -1 ../*.patch:通过执行 ls 命令列出上一级目录(..)中以 .patch 结尾的所有文件,并使用 -1 选项确保每个文件显示为一行。这将生成一个包含所有补丁文件名的列表。
# for p in ...; do ...; done:通过循环结构遍历列表中的每个元素,并在循环体内执行相应的操作。这里对列表中的每个元素都被赋值给变量 p。
# patch -p1 < $p:对于每个补丁文件 $p,执行 patch 命令来应用补丁文件到当前目录。-p1 选项告诉 patch 命令去除补丁文件中的前缀路径(通常是一个目录),从而使补丁适用于当前目录。
# 循环遍历上一级目录中的所有以 .patch 结尾的文件,并使用 patch 命令将这些补丁文件应用到当前目录中,其中补丁文件的前缀路径被去除

 

3. 生成默认配置文件

  ST 原厂 Linux 内核需要先生成默认配置文件,并且对其进行打补丁,进入 Linux 内核源码根目录下,然后执行如下命令: 

make ARCH=arm multi_v7_defconfig "fragment*.config"

# multi_v7_defconfig:指定要使用的配置文件。
# "fragment*.config":用于指定附加的配置片段文件。这里的 "fragment*.config" 是通配符表达式,指定了以 fragment 开头且以 .config 结尾的文件名模式。

  .config 文件非常重要, Linux 内核的所有配置项最终都保存在.config 文件里面,最终编译Linux 内核的时候需要读取.config 里面的配置项!此时我们只是生成了.config,并没有将 fragment config 补丁文件打进去,执行如下命令 

for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done
yes '' | make ARCH=arm oldconfig

# scripts/kconfig/merge_config.sh -m -r .config $f:执行 merge_config.sh 脚本,将文件 $f 的配置合并到当前目录的 .config 文件中。-m 选项表示使用模块化配置,-r 选项表示要保留已经存在的配置。
# yes '':yes 命令会重复地输出指定的字符串(在本例中是空字符串 ''),直到被终止
# ARM 架构上使用旧的配置 .config 文件执行 make oldconfig,并在自动回答用户提示时使用空字符串来完成配置过程。这样可以自动化配置过程,减少了手动输入配置的需要

  至此, Linux 源码根目录下的.config 文件就已经保存了所有的配置项,所以只需要复制一份.config 作为我们的默认配置文件即可,复制命令如下: 

cp .config ./arch/arm/configs/stm32mp1_atk_defconfig

  Linux 内核全部打完补丁, linux-5.4.31 目录就是我们要移植的 Linux 源码。我们新建一个名为“my_linux”的目录来保存我们要移植的 linux 源码,然后将打完补丁的 linux 源码 linux-5.4.31 拷贝到“my_linux”目录下,命令如下: 

# 首先在/linux/atk-mpl创建 linux 目录,然后再linux目录下创建my_linux子目录
cd ~
cd linux/atk-mpl/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/
cp linux-5.4.31 /linux/atk-mpl/linux/my_linux/ -rf //拷贝

 

 

二、编译 ST 官方 Linux 源码 

1. 修改Makefile

  其实跟uboot修改顶层 Makefile 一样,为了减少输入参数,就添加以下代码到顶层 Makefile 中。

  创建一个名为“stm32mp157d_atk.sh”的编译脚本,脚本内容如下: 

#!/bin/sh
make distclean
make stm32mp1_atk_defconfig
make menuconfig
make uImage dtbs LOADADDR=0XC2000040 -j16

  给 stm32mp157d_atk.sh  执行权限:

chmod 777 stm32mp157d_atk.sh     // 给予可执行权限
./stm32mp157d_atk.sh             // 运行编译脚本

  编译完成以后的到 uImage 镜像文件和设备树,其中 STM32MP157 系列的设备树有很多。

 

 

2. 修改网络驱动

  文件均来自正点原子的包里,下载地址:STM32MP157开发板 — 正点原子资料下载中心 1.0.0 文档

  将 motorcomm.c motorcomm_phy.h 分别拷贝到 Linux 源码下的 drivers/net/phy include/linux 目录下。拷贝完成以后修改 drivers/net/phy/Makefile 文件,加上下面这句: 

obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o

# 如果定义了配置选项 CONFIG_MOTORCOMM_PHY 并且其值为 true,那么目标 motorcomm.o 将被添加到目标列表中,进而进行编译。

 

  还需要修改 drivers/net/phy/Kconfig 文件,添加以下代码:

config MOTORCOMM_PHY
    tristate "Motorcomm PHYs"
    ---help---
    Supports the YT8010, YT8510, YT8511, YT8512 PHYs.
    
/* config MOTORCOMM_PHY:定义了一个名为 MOTORCOMM_PHY 的配置选项。这个配置选项可用于在编译内核时启用或禁用与 Motorcomm PHY 相关的功能。

tristate "Motorcomm PHYs":配置选项的类型被设置为 tristate,即可以选择三个状态:y(编译进内核), m(编译为模块)和 n(禁用)。
"Motorcomm PHYs" 是配置选项的显示名称,将显示在配置界面上。

---help---:用来提供配置选项的帮助说明。该行以下的内容将被视为对配置选项的详细描述。

Supports the YT8010, YT8510, YT8511, YT8512 PHYs.:是对配置选项的详细描述,说明该选项的作用是支持 YT8010、YT8510、YT8511 和 YT8512 PHY 模块。
我们可以在 Linux 内核构建过程中选择是否编译或加载与 Motorcomm PHY 相关的功能模块*/

 

   在终端输入 make menuconfig,进入以下路径:

-> Device Drivers
    -> Network device support (NETDEVICES [=y])
        -> PHY Device support and infrastructure (PHYLIB [=y])
            -> <*> Motorcomm PHYs //将 YT8511 驱动编译进内核

 

./stm32mp157d_atk.sh   //运行编译脚本

3. 启动测试

  需要两个文件: uImage stm32mp157d-ed1.dtb 

  首先将 /home/alientek/linux/tftpboot 文件删除,然后把这两个文件复制到tftp目录下并给予执行权限,命令如下:

cp stm32mp157d-ed1.dtb /home/alientek/linux/tftpboot/
cd ..
cp uImage /home/alientek/linux/tftpboot/
cd ~
cd linux/tftpboot/
chmod 777 stm32mp157d-ed1.dtb
chmod 777 uImage

  在 uboot 中输入:

tftp c2000000 uImage
tftp c4000000 stm32mp157d_ed1.dtb
bootm c2000000 - c4000000

 

三、在 Linux 中添加自己的开发板

1. 添加开发板对应的默认配置文件 

  首先添加开发板对应的默认配置文件,这里输入以下命令:

cd linux/atk-mpl/linux/my_linux/linux-5.4.31/arch/arm/configs
find stm32mp1_atk_defconfig

  就可以找到  stm32mp1_atk_defconfig  这个文件了。

 

2. 添加开发板对应的设备树 

 ① 新建设备树文件

   输入以下命令:

cd ~
cd linux/atk-mpl/linux/my_linux/linux-5.4.31/arch/arm/boot/dts/
cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi
cp stm32mp157d-ed1.dts stm32mp157d-atk.dts

  修改  stm32mp157d-atk.dts  文件:

 

 ② 修改 stm32mp157d-atk.dtsi 文件 

   跟uboot移植类似,PMIC 配置不需要,并在设备树里面添加电源节点信息。

#include "stm32mp157-m4-srm.dtsi"
#include "stm32mp157-m4-srm-pinctrl.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/mfd/st,stpmic1.h>

/ {
    memory@c0000000 {
        device_type = "memory";
        reg = <0xC0000000 0x40000000>;
    };

    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        mcuram2: mcuram2@10000000 {
            compatible = "shared-dma-pool";
            reg = <0x10000000 0x40000>;
            no-map;
        };

        vdev0vring0: vdev0vring0@10040000 {
            compatible = "shared-dma-pool";
            reg = <0x10040000 0x1000>;
            no-map;
        };

        vdev0vring1: vdev0vring1@10041000 {
            compatible = "shared-dma-pool";
            reg = <0x10041000 0x1000>;
            no-map;
        };

        vdev0buffer: vdev0buffer@10042000 {
            compatible = "shared-dma-pool";
            reg = <0x10042000 0x4000>;
            no-map;
        };

        mcuram: mcuram@30000000 {
            compatible = "shared-dma-pool";
            reg = <0x30000000 0x40000>;
            no-map;
        };

        retram: retram@38000000 {
            compatible = "shared-dma-pool";
            reg = <0x38000000 0x10000>;
            no-map;
        };
    };

    vddcore: buck1 {
        compatible = "regulator-fixed";
        regulator-name = "vddcore";
        regulator-min-microvolt = <1200000>;
        regulator-max-microvolt = <1350000>;
        regulator-always-on;
        regulator-boot-on;
    };

    v3v3: regulator-3p3v {
        compatible = "regulator-fixed";
        regulator-name = "v3v3";
        regulator-min-microvolt = <3300000>;
        regulator-max-microvolt = <3300000>;
        regulator-always-on;
        regulator-boot-on;
    };
};

&cpu0 {
    cpu-supply = <&vddcore>;
};

&crc1 {
    status = "okay";
};

&dma1 {
    sram = <&dma_pool>;
};

&dma2 {
    sram = <&dma_pool>;
};

&dts {
    status = "okay";
};

&ethernet0 {
    status = "okay";
    pinctrl-0 = <&ethernet0_rgmii_pins_a>;
    pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
    pinctrl-names = "default", "sleep";
    phy-mode = "rgmii-id";
    max-speed = <1000>;
    phy-handle = <&phy0>;

    mdio0 {
        #address-cells = <1>;
        #size-cells = <0>;
        compatible = "snps,dwmac-mdio";

        phy0: ethernet-phy@0 {
            reg = <0>;
        };
    };
};

&hash1 {
    status = "okay";
};

&ipcc {
    status = "okay";
};

&iwdg2 {
    timeout-sec = <32>;
    status = "okay";
};

&rng1 {
    status = "okay";
};

&rtc {
    status = "okay";
};

&sdmmc1 {
    pinctrl-names = "default", "opendrain", "sleep";
    pinctrl-0 = <&sdmmc1_b4_pins_a>;
    pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
    pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
    broken-cd;
    st,neg-edge;
    bus-width = <4>;
    vmmc-supply = <&v3v3>;
    status = "okay";
};

&sdmmc2 {
    pinctrl-names = "default", "opendrain", "sleep";
    pinctrl-0 = <&sdmmc2_b4_pins_a>;
    pinctrl-1 = <&sdmmc2_b4_od_pins_a>;
    pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>;
    non-removable;
    st,neg-edge;
    bus-width = <8>;
    vmmc-supply = <&v3v3>;
    keep-power-in-suspend;
    status = "okay";
};

&sram {
    dma_pool: dma_pool@0 {
        reg = <0x50000 0x10000>;
        pool;
    };
};

&uart4 {
    pinctrl-names = "default", "sleep", "idle";
    pinctrl-0 = <&uart4_pins_a>;
    pinctrl-1 = <&uart4_sleep_pins_a>;
    pinctrl-2 = <&uart4_idle_pins_a>;
    pinctrl-3 = <&uart4_pins_a>;
    /delete-property/dmas;
    /delete-property/dma-names;
    status = "okay";
};

  这里是替换整个文件的代码,直接复制进去即可。

 ③ 编译 stm32mp157d-atk.dts 设备树

  打开 arch/arm/boot/dts/Makefile,到“ dtb-$(CONFIG_ARCH_STM32)”配置项,在此配置项中加入“stm32mp157d-atk.dtb”, 表示编译的时候也将 stm32mp157datk.dts 编译为 stm32mp157d-atk.dtb 。

 

3. 关闭内核模块验证

  后续做 Linux 驱动实验的时候我们都是编译驱动模块,然后在系统里面加载,加载的时候系统会验证模块,有时候会验证出错。比如板子运行的系统和编译驱动模块所用的系统不一致的时候。为了方便开发,我们可以关闭内核模块验证。打开默认配置文件 stm32mp1_atk_defconfig,里面有如下所示配置项目: 

 

  我们也可以直接在 Linux 的图形化配置界面上关闭掉内核模块验证,输入如下命令打开 Linux 内核图形化配置界面: 

# 在 /linux/atk-mpl/linux/my_linux/linux-5.4.31 该目录下
make menuconfig

# 配置路径如下:
-> Enable loadable module support (MODULES [=y])
    ->Module signature verification

  

 

  只要通过图形化界面修改了 Linux 内核配置,最好及时将其保存到stm32mp1_atk_defconfig 文件。因为图形化界面修改的配置只是暂时保存到.config 文件里面,一旦使用“make clean”清理工程,那么.config 文件就会被删除掉,所有的配置也就丢失了!

 

4. 编译测试

  进入该目录 /linux/atk-mpl/linux/my_linux/linux-5.4.31,再编译 stm32mp157d_atk.sh。二、3启动测试类似,把文件拷贝到 tftp 服务器目录下。在uboot下输入以下命令。

tftp c2000000 uImage
tftp c4000000 stm32mp157d-atk.dtb
bootm c2000000 - c4000000

 

  有这样的 log 信息就启动成功。

 

四、烧写系统镜像到 EMMC  

  我们现在都是通过 tftp 命令从网络上下载测试的,实际产品开发中最终是要将系统烧写到外部 Flash 中的,比如 EMMC现在我们uIamge stm32mp157d-atk.dtb 打包成 ext4 格式,然后通过 STM32CubeProgrammer 烧写到 EMMC 里面,最终启动 EMMC 里面的 Linux 系统。

 

1. 系统镜像打包

  先在 linux/atk-mpl/linux/ 路径下创建子目录 bootfs,然后再把 /linux/tftpboot 路径下的 stm32mp157d-atk.dtb 和 uImage 文件拷贝到 bootfs 里面。

① 新建 ext4 格式磁盘

  首先新建一个 ext4 格式的磁盘,然后挂载这个 ext4 格式的磁盘,将 stm32mp157d-atk.dtb uImage 拷贝到这个 ext4 磁盘即可。 

cd bootfs
dd if=/dev/zero of=bootfs.ext4 bs=1M count=10
mkfs.ext4 -L bootfs bootfs.ext4    # 使用 mkfs.ext4 将 bootfs.ext4 磁盘格式化为 ext4 格式

# 使用 dd 命令创建一个名为 bootfs.ext4 的磁盘, of 指定磁盘名字为“bootfs.ext4”;bs 指定磁盘输入/输出块大小为 1MB; count 指定磁盘的块数量为 10 个。
# 将会在当前目录下创建一个大小为10MB的bootfs.ext4文件,并用零填充它。

 

 

将系统镜像拷贝到 ext4 磁盘中

  首先创建一个目录用来挂载前面制作制作出来的 bootfs.ext4,比如我这里创建目录/mnt/bootfs,命令如下: 

cd /
sudo mkdir /mnt/bootfs

  使用 mount 命令将 bootfs.ext4 挂载到/mnt/bootfs 目录下,命令如下: 

cd /home/alientek/linux/atk-mp1/linux/bootfs
sudo mount bootfs.ext4 /mnt/bootfs

  挂载成功以后就将 uImage stm32mp157d-atk.dtb 拷贝到/mnt/bootfs 目录下,命令如下: 

sudo cp uImage stm32mp157d-atk.dtb /mnt/bootfs/

  拷贝完成以后使用 umount 卸载/mnt/bootfs 即可,命令如下: 

sudo umount /mnt/bootfs

  这里我的理解是:先创建.ext4 磁盘,这个磁盘必须挂在到目录下,把需要放在这个磁盘下的东西放在挂载的目录里,最后再卸载该目录下的挂载。

 

2. 烧写到 EMMC 

  利用 FileZilla 将 bootfs.ext4 拷贝到 image 目录下:

  修改 Flashlayout:

  先把拨片波到USB,然后烧写,烧写完成后,把拨片拨到 EMMC 然后 RESET ,在 uboot 输入以下命令来验证是否烧写了  uImage stm32mp157d-atk.dtb 

ext4ls mmc 1:2

 

  设置 bootcmd 环境变量,从 EMMC 里面读取系统镜像和设备树并启动,命令如下:

setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157d-atk.dtb;bootm c2000000 - c4000000'
saveenv
boot

  一般情况下,调试阶段都是用网络调试,也就是 tftp 或 nfs,当最终产品开发完成后,出厂的时候才烧写到 EMMC 里面。

 

五、文件系统缺失错误   

  Linux 内核启动以后是需要根文件系统的,根文件系统存在哪里是由 uboot bootargs 环境变量指定的,它会传递给 Linux 内核作为命令行(command line)参数。  没有对应的根文件系统,必须要自己做根文件系统。 在没有根文件系统的情况下, Linux 内核启动的时候就会有下图所示的错误: 

 

  也就是提示内核崩溃, VFS(虚拟文件系统)不能挂载根文件系统,因为根文件系统目录不存在。解决方法就是制作根文件系统,并且设置 uboot bootargs 环境变量,指定根文件系统所在的目录。 

本文作者:烟儿公主

本文链接:https://www.cnblogs.com/toutiegongzhu/p/17604409.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   烟儿公主  阅读(452)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 夏日大冒险 暴躁的兔子
夏日大冒险 - 暴躁的兔子
00:00 / 00:00
An audio error has occurred.

作词 : 暴躁的兔子

作曲 : 暴躁的兔子

编曲 : IOF

混音:Gfanfan

出品:网易飓风

夏天 不要再浪费时间

实现 你承诺过的改变

别再 找一堆借口拖延

现在就和我一起飞向海边

人生苦短 你应该学会如何作乐

低着头还怎么应对挫折

人应该为自己活着

不用去迎合

要去寻欢作乐

撮合我的浪漫和悲欢

把这荒诞人生都塞满

生活难免磕磕绊绊

对抗生活的平庸就是浪漫

学会取悦自己逆风翻盘

去反抗变态的三观

把条条框框都砸烂

建立新的规则推翻谈判

无可救药的人呐

和我一起去海边

看那日出和晚霞 海天一线

看阳光穿越地平线

现实交织的明天

就在这个夏天

为自己改变

别怕山高路远

去冒险

我真的不care你是否会喜欢我

不跟风被定义的美 全都是灾祸

我才不讨好大多数绝不与示弱

过好你的生活

你管我应该怎么快活

没有人能有资格审判

别人的生活和牵绊

快闭上你的高谈阔论

乘风破浪吧 理想的风帆

我就是肆意张扬又如何

我就是锋芒毕露又如何

我就是离经叛道又如何

我就是要出格 你管我要如何

我就是与众不同又如何

我就是特立独行又如何

我就是不知好歹又如何

你管我怎样出格 你管我如何

无可救药的人呐

和我一起去海边

看那日出和晚霞 海天一线

看阳光穿越地平线

现实交织的明天

就在这个夏天

为自己改变

别怕山高路远

不知进退的人呐

和我一起去海边

聊聊曾经的理想 一起想当年

那曾想改变世界的人

是否还满腔热忱

不羁的我们放肆着

反抗那命运的指针

解放灵魂

推广:网易飓风

企划:贾焱祺

监制:徐思灵

出品人:谢奇笛