7 Linux 内核移植

2023-11-06

一、编译 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 驱动编译进内核

 

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 环境变量,指定根文件系统所在的目录。 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

7 Linux 内核移植 的相关文章

随机推荐

  • VI/VIM 键盘图 及常规快捷操作

    一 VI VIM 键盘图 二 模式转换 2 1 一般模式 2 2 编辑模式 2 3 命令模式
  • EasyExcel导出图片到Excel

    EasyExcel导出图片到Excel 需要自己重新写转换器 但是1000张以下导出是没问题的 10000以上会卡顿 有意向的小伙伴可以一起讨论下 如何处理大数量的图片导出到excel import com alibaba excel co
  • GCC详解-总览

    1 GCC是什么 早期 GCC 的全拼为 GNU C Compiler 即 GUN 计划诞生的 C 语言编译器 显然最初 GCC 的定位确实只用于编译 C 语言 但经过这些年不断的迭代 GCC 的功能得到了很大的扩展 它不仅可以用来编译 C
  • 数字IC设计学习笔记_静态时序分析STA_配置STA环境2

    数字IC设计学习笔记 配置STA环境2 1 约束 Input path 和 Output path 2 时序路径组Timing path groups 3 外部属性建模 1 约束 Input path 和 Output path 约束 In
  • 【华为OD机试真题 python】识图谱新词挖掘【2023 Q1

    题目描述 识图谱新词挖掘 小华负责公司知识图谱产品 现在要通过新词挖掘完善知识图谱 新词挖掘 给出一个待挖掘文本内容字符串Content和一个词的字符串word 找到content中所有word的新词 新词 使用词word的字符排列形成的字
  • ES6入门:iterator迭代器

    迭代模式 ES6迭代器标准化接口 迭代循环 自定义迭代器 迭代器消耗 一 迭代模式 迭代模式中 通常有一个包含某种数据集合的对象 该数据可能存在一个复杂数据结构内部 而要提供一种简单的方法能够访问数据结构中每个元素 对象消费者并不需要知道如
  • 二、redis中String和List两种数据类型和应用场景

    导读 前面文章 一 深入理解redis之需要掌握的知识点 中 我们对redis需要学习的内容进行了一个梳理 从本篇文章开始 我们将要对redis中各个知识点做详细的学习和分析 本篇文章我们学习的是redis中基础数据类型String和Lis
  • matlab如何求矩阵特征值

    根据线性代数理论 特征值与特征向量只存在于方阵 如下所示为一方阵A 在matlab输入矩阵 A 1 2 4 4 0 7 9 1 3 查阅matlab help可以知道 利用eig函数可以快速求解矩阵的特征值与特征向量 格式 V D eig
  • 【踩坑】AES256解密失败,jasypt解密失败 最简单解决办法(本地环境)

    背景 最近被拉去一个新项目组 他们用的jasypt加密方式为数据库信息加密 我拉取代码后一跑 果然报错了 Unable to decrypt ENC xxxx 在试了n中方法 包括 创建新项目使用jasypt复现 写demo直接用jasyp
  • 给你们讲个笑话——低代码会取代程序员

    今天是正经男 我们严肃讨论一下一直以来争吵不休的取代问题 低代码开发平台 低代码技术会取代开发人员么 一 背景 低代码开发平台的普及 让很多公司对快速生成应用抱有很大期望 甚至有人认为 低代码开发平台未来会 干掉 开发者 这是真的吗 好久没
  • 压缩感知入门

    学习资料 网站http dsp rice edu cs 具有相关大量详细介绍的论文
  • idea 编译和构建 Java Web 项目后,没有生成 target 文件夹,且生成的 out 文件夹中没有 class 文件

    问题 在用 idea 编译和构建 Java Web 项目的时候 项目的目录中没有 target文件夹 生成的 out 文件夹中 没有 class 文件 办法 出现这种情况 很可能是因为未加载的模块出现在了 iml 文件中 导致生成 tage
  • Unity Animation -- 导入动画

    尽管Unity中的动画工具已经比较强大了 但对于非常复杂的或很长的动画 通常是由外部DCC创建 特别是对于角色动画来说 需要在动画过程中进行复杂的控制 因此我们通常需要将外部制作的动画导入到Unity中 动画能被共享吗 对于复杂的动画 制作
  • 阿里云-对象存储OSS

    大家好 我是 码赛客1024 今天我们一起来学习阿里云的对象存储服务OSS 一 介绍 阿里云对象存储OSS Object Storage Service 是一款海量 安全 低成本 高可靠的云存储服务 提供99 9999999999 12个9
  • 树的高度和深度

    用到树的数据结构时 经常会考虑树的高度和深度 但是lz总是搞混了 总虽然比较简单 就是个定义 记住就行了 但是因为长时间总是弄错 所以写一篇博文 加深一下印象 1 树的深度 树的深度可以这样理解 计算一个节点的深度 从根节点算起 记住从1开
  • LeetCode 之 Search for a Range

    题目链接 Search for a Range 对于一个按照升序排序的整数数组 找到给定目标值的开始位置和结束位置 且时间复杂度为O log n 如果在数组中找不到目标值 则返回 1 1 例如 数组为 5 7 7 8 8 10 和目标值8
  • PyTorch搭建LSTM实现时间序列预测(负荷预测)

    目录 I 前言 II 数据处理 III LSTM模型 IV 训练 V 测试 VI 源码及数据 I 前言 在上一篇文章深入理解PyTorch中LSTM的输入和输出 从input输入到Linear输出 中 我详细地解释了如何利用PyTorch来
  • qt中复制文件的功能

    1 利用qt来复制文件 首先新建个工程文件 拖入按钮 复制文件 2 需要引入的头文件如下 include
  • 六月学习记录

    六月学习记录 6 1 Android消息传递之Handler消息机制 four articles http www cnblogs com whoislcj p 5590615 html 6 2 代码审查工具phabricator 6 4
  • 7 Linux 内核移植

    一 编译 ST 的 Linux 系统 1 压缩源码 首先先下载 ST 官方源码 之前章节已经下载过了 直接输入以下命令 cd linux atk mpl stm32mp1 openstlinux 5 4 dunfell mp1 20 06