ARM kernel 内核的移植 - 从三星官方内核开始移植

news2024/11/15 7:56:10

一、内核移植初体验

1、三星官方移植版内核获取

(1) 从网盘下载源码包。

(2) 这个文件最初是来自于三星的 SMDKV210 开发板附带的光盘资料。

在这里插入图片描述


2、构建移植环境

(1) Windows下建立工程。
在这里插入图片描述


(2) ubuntu下解压。

在这里插入图片描述


3、配置编译下载尝试

(1) 检查 Makefile 中 ARCH 和 CROSS_COMPILE。

在这里插入图片描述


(2) make smdkv210_android_defconfig。
(3) make menuconfig。
(4) make -j4。

默认情况下直接 make,则会直接单线程编译。但是如果 make -j4, 则会 4 线程编译。

在这里插入图片描述


4、后续要做的事情:

(1) 编译得到的 zImage 去下载运行,看结果。

(2) 根据结果去分析问题原因,然后去尝试解决这些问题。

注意:使用的 uboot,是 x210 的 uboot。

在这里插入图片描述

在这里插入图片描述


二、初步移植以看到启动信息

在这里插入图片描述

1、分析问题

(1) 根据运行结果,分析发现:linux 内核的自解压代码都没有运行(因为没有看到:Uncompressing Linux… done, booting the kernel.

在这里插入图片描述


(2) 说明 zImage 根本没有被解压成功,内核代码根本就没有被运行,当然没有输出信息了。所以问题出在解压相关的部分。

(3) 问题出在,内核配置的解压后代码放置的内存地址处。

(4) 内核配置的解压地址,应该等于链接地址,否则自解压之后内核无法运行。

现在问题变成:
第一,内核的链接地址等于多少?
第二,内核中配置的解压地址是多少?


(5) 这里面还有个问题:内核的链接地址是一个虚拟地址,而自解压代码解压内核时,需要物理地址;因此上面说的,其实是链接地址对应的物理地址等于自解压地址。

在这里插入图片描述


(6) 链接地址和它对应的物理地址在 head.S 中可以查到,分别是 0xC00080000x30008000 。那么自解压代码配置的解压地址应该是 0x30008000.

在这里插入图片描述

在这里插入图片描述


(7) 自解压代码对应的自解压地址在 mach/Makefile.boot 文件中。在其中修改,加入两行:

# override for SMDKV210
zreladdr-$(CONFIG_MACH_SMDKV210)	:= 0x30008000
params_phys-$(CONFIG_MACH_SMDKV210)	:= 0x30000100

在这里插入图片描述


(8) 同步代码,并且编译,得到的 zImage 复制到 tftp 服务器,然后重新下载运行查看结果。

在这里插入图片描述


三、内核中机器码的确定

1、MACHINE_START 宏

(1) 这个宏 用来定义一个机器码的数据结构的。这个宏的使用,其实是用来定义一个结构体类型为 machine_desc 类型的结构体变量,名为 __mach_desc__type 。这个结构体变量,会被定义到一个特定段 .arch.info.init,因此这个结构体变量将来会被链接器链接到这个 .arch.info.init 段中。

在这里插入图片描述


(2) 经过分析,发现一个 mach-xxx.c 文件中定义了一个机器码的开发板的machine_desc 结构体变量,这个结构体变量放到 .arch.info.init 段中后,那么就表示当前内核可以支持这个机器码的开发板。

在这里插入图片描述


(3) 落实到当前开发板和当前内核中来分析,当前我们移植的目标开发板使用 S5PV210 的 CPU,开发板名字叫 X210。

我们在三星官方版本的内核中是找不到 mach-x210.c 的,所以我们又不想从零开始去移植,因此我们的思路是,在三星移植的 mach-s5pv210 目录下找一个 mach-xx.c,这个开发板和我们的 X210 开发板最为接近,然后以此为基础来移植。


(4) 经过查看,发现 mach-s5pc110.c 和 mach-s5pv210.c 和我们的 X210 开发板最为接近。我们一般确定的一个原则是:看我们的开发板和三星官方的哪个开发板最为相似。

在这里插入图片描述

我们的 X210 开发板抄的是三星的 SMDKV210,因此要找这个对应的那个文件。


(5) 结合 mach-s5pv210 目录下的 Makefile 来分析,得知 .config 中定义了CONFIG_MACH_SMDKV210 后,实际绑定的是 mach-smdkc110.c 这个文件。

在这里插入图片描述

所以实际上,mach-smdkv210.c 这个文件根本没用到。启示就是:不要光看名字。


2、硬件驱动的加载和初始化函数执行

(1)

.init_machine	= smdkc110_machine_init,

在这里插入图片描述


(2) 这个元素定义了一个机器硬件初始化函数,这个函数非常重要,这个函数中绑定了我们这个开发板 linux 内核启动过程中,会初始化的各种硬件的信息。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


四、解决内核启动中的错误

1、认识内核启动OOPS

(1) 内核启动后会有打印信息,打印信息中隐藏了问题所在。认真的去分析这个打印信息,从中找到对的或者错误的一些信息片段,才能帮助我们找到问题,从而解决问题。


(2) 内核启动中的错误信息有一些特征:

在这里插入图片描述


(3) 从以上错误信息中的 PC 和 LR 的值可以看出,程序是执行到 dev_driver_string 或者 max8698_pmic_probe(这两个是函数或者汇编中的标号)符号部分的时候出错了。我们就从这两个符号出发去寻找、思考可能出错的地方然后试图去解决。


2、错误追溯及问题解决

(1) max8698_pmic_probe 看名字是 max8698 这个电源管理 IC 的驱动安装函数部分出错了,应该是我们的开发板系统中配置了支持这个电源管理 IC,于是启动时,去加载它的驱动,结果驱动在加载执行的过程中出错了 OOPS 了。


(2) 我们为什么要配置支持这个驱动?这个驱动加载为什么要出错?


(3) 结合我们 X210 开发板的硬件实际情况来分析:我们 X210 开发板上根本就没有 max8698 这个电源管理 IC,既然硬件都没有,驱动执行了肯定会出错。


(4) 回忆当时从三星版本的 uboot 移植的时候,在 uboot 的 lowlevel_init.S 中也有调用过电源管理 IC 初始化函数(PMIC_init),后来解决的办法就是屏蔽掉了这个函数的调用,uboot 就成功运行下去了。


(5) 为什么我们的 uboot 和内核中默认都调用了这个电源管理 IC的初始化代码?

原因就是,三星的 SMDKV210 开发板中是用了 max8698 这个电源管理 IC 的,所以三星的 uboot 和 kernel 中都有默认支持这个。但是 X210 中是没用的,因此都需要去掉。


(6) 怎么解决?

在 uboot 中是直接改源代码,屏蔽掉那个初始化函数解决的;

在内核中不能这么干?因为 linux kernel 是高度模块化高度可配置的,内核中每一个模块都是被配置项条件编译了的,因此要去掉某个模块的支持,只需要重新配置去掉选项即可,不用改源代码。所以我们的关键就是要找它对应的配置项。


(7) 我们的做法:make menuconfig,然后斜杠搜索(/MAX8698)这几个关键字,然后看到这个配置项的路径,然后到路径下去按 N 键去掉这个模块的支持,保存,重新编译即可。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


(8) 实践证明问题被解决了,而且内核再次启动后直接运行到挂载 rootfs 才出错。

在这里插入图片描述

在这里插入图片描述


3、分析及总结

(1) 分析:问题究竟是怎么被解决的?涉及哪几个方面。

根本原因在于 CONFIG_MFD_MAX8698 这个配置宏。这个配置宏决定了很多东西。

第一:这个配置宏 决定了 drivers 目录下的 max8698 对应的驱动程序源代码是否被编译。
第二:这个配置宏 决定了 kernel 启动过程中是否会调用一些 max8698 的相关的代码。

在这里插入图片描述


(2) 总结:kernel 是高度模块化和可配置化的,所以在内核中做任何事情(添加一个模块、更改一个模块、去掉一个模块)都必须按照内核设定的方案和流程来走。


五、iNand 的问题和安排

1、错误分析

(1) 得到的内核错误信息:

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

从错误信息字面意思来分析,就是内核试图挂载根文件系统时失败,失败的原因是unknown-block(不能识别的块设备)。

在这里插入图片描述


(2) Backtrace 分析,可以得知错误信息的来源,再结合之前的内核启动流程分析,就更加确定了出错的地方。


(3) 下一个问题:分析这个错误出现的原因:unknown-block(0,0)。

在 kernel 启动时,uboot 会传给内核一个 cmdline,其中用 root=xx 来指定了 rootfs 在哪个设备上,内核就会到相应的地方去挂载 rootfs。

譬如我们传参中:root=/dev/mmcblk0p2,这里的 /dev/mmcblk0p2 就是 rootfs 的设备地址,这个设备文件编号的含义就是:mmc 设备 0 的第 2 个分区(设备 0 就是在 SD0 通道上的设备,也就是 iNand),这里的问题就是,没找到mmc 设备 0 的第2分区。


(4) 下一步问题:为什么没找到 mmc 设备 0 的第 2 分区。一定是因为 kernel 启动过程中加载 mmc 驱动的时候有问题,驱动没有发现 mmc 设备 0。问题定位在 MMC 相关的驱动方面。


(5) 对比九鼎版本的内核启动信息,即可发现:我们的内核启动并没有找到 MMC 设备(内置的 iNand 和外置的 SD 卡都没找到),没找到肯定是驱动的问题,这就要去移植 MMC 驱动了。

九鼎 kernel :

在这里插入图片描述


三星官方 kernel:

在这里插入图片描述


2、问题阐述

(1) SD/iNand 本身都是由一个一个的扇区组成的,回忆裸机中讲到的 210 的启动时,BL1 在 SD 卡的 1 扇区开始往后存放,SD 卡的 0 扇区是不用的。SD 卡的 0 扇区是用来放置 MBR 的

在这里插入图片描述


(2) MBR 就是用来描述块设备的分区信息的, 事先定义了一个通用的数据结构来描述块设备的分区,我们只要按照这个标准,将分区信息写入 MBR 中,即可对该设备完成分区。MBR 默认就是在块设备的第 0 个扇区上存放的。


(3) 我们内核中读到 iNand 分 4 个分区,我们是在哪里分区的?uboot 中有一个命令 fdisk -c 0 时,就对 iNand 进行了分区。uboot 的 fdisk 命令内部已经写死了 iNand 的分区表,到内核中时,内核直接读取 MBR 就知道了分区。所以在 uboot 和内核之间 iNand 设备的分区信息是靠 iNand 自己传递的,所以 uboot 不用给内核传参时 传递分区表信息。

在这里插入图片描述

在这里插入图片描述


(4) 如果开发板用的是 nandFlash 的话,分区表一般是在内核中自己用代码构建的。所以 nand 版本的内核移植的时候,一般都需要去移植更改 nand 分区表。


3、解决安排

(1) 暂时解决不了这个问题。


4、后续课程安排

(1) 一节课搞定网卡驱动的移植,一节课讲述一些内核移植的小方法和技巧,然后课程结束。


(2) 整体移植的课程结束,进入根文件系统部分。


六、网卡驱动的移植和添加实验

1、移植标准

(1) 网卡驱动移植 ok 时,启动信息为:

[    1.452008] dm9000 Ethernet Driver, V1.31
[    1.455870] eth0: dm9000c at e08f4300,e08f8304 IRQ 42 MAC: 00:09:c0:ff:ec:48 (platform data)

在这里插入图片描述


(2) 当前内核中网卡驱动尚未移植,因此内核启动时有错误的打印信息:

在这里插入图片描述


(3) 移植的目标就是,让我们的版本的内核可以打印出正确情况下的启动信息,那我们就相信内核启动后网卡是可以工作的。


2、make menuconfig 中添加 DM9000 支持

(1) menuconfig 中选择 Y。

(2) 其实这一步本来就是 Y,所以在我们这里是不用管的。但是你自己遇到的一个内核可能默认不是 Y,因此要设置。


3、mach-smdkc110.c 中逻辑分析

(1) mach-smdkc110.c 中的 smdkc110_machine_init 是整个开发板的所有硬件的初始化函数,在这里加载了的硬件, 将来启动时就会被初始化,在这里没有的,将来启动时就不管。

在这里插入图片描述


(2) smdkc110_devicessmdkc110_dm9000_set() 这两个地方是和 DM9000 有关的,要分别去做移植。
在这里插入图片描述


(3) smdkc110_dm9000_set 这个函数就是 DM9000 相关的SROM bank 的寄存器设置,相当于 uboot 中 dm9000 移植时的 dm9000_pre_init 函数。只是读写寄存器的函数名称不同了。

在这里插入图片描述

在这里插入图片描述


4、修改相应的配置参数

(1) DM9000 相关的数据配置在 arch/arm/plat-s5p/devs.c 中更改。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


(2) 在 arch/arm/mach-s5pv210/include/mach/map.h 中定义了 DM9000 的 IO 基地址,和 DM9000 接在哪个bank有关。

在这里插入图片描述


(3) 还有 +2 改成 +4,IRQ_EINT9 改成 10 即可。

在这里插入图片描述


5、代码实践

(1) 同步代码、编译生成 zImage。

(2) 下载启动后看启动信息。

在这里插入图片描述


七、内核启动第一阶段的调试方法

1、问题点描述

(1) 内核启动在 head.S 中首先进行了三个校验(CPU id 的校验、机器码的校验、tag 的校验),然后创建页表,然后做了一些不太会出错的事情,然后 b start_kernel。基本上能运行到 start_kernel ,内核移植就不太会出问题了。

在这里插入图片描述


(2) 有时候,移植的内核启动后的现象是:根本没有启动信息出来。

这时候,有可能是内核启动运行了,但是运行出错了没启动起来,所以没有打印信息;

也有可能是内核根本没得以运行。

都有可能但是没法确定。我们希望能有一种调试手段来确定问题所在。


2、调试方法和原理

(1) 调试方法就是,在内核启动的第一阶段添加汇编操作 led 点亮/熄灭的方法,来标明代码运行的轨迹。

(2) 我们找之前裸机中汇编操作 led 点亮/熄灭的代码过来,复制粘贴到 head.S 中合适位置。然后内核启动后,根据 led 的表现来标明代码有无运行。


3、动手测试

(1) 整理好 led 操作的代码段,在 head.S 中合适的地方添加 led 这个函数,然后在 head.S 的内核起始运行阶段添加调用 led 函数,然后重新编译内核,运行内核看这段代码有无被运行。

在这里插入图片描述


(2) 如果被运行了,证明在这个调用 led 的步骤之前的部分,都是没问题的,那么如果有错,肯定错误在后边;

如果没有被运行,则证明错误在之前,那么就要去之前的部分debug。


4、实验验证


源自朱有鹏老师.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/440319.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手把手教你Python爬虫

前言 python爬虫技术在java开发工作中属于工具性的技术属性,所以我这里就只从爬取一个网站的数据为例作为教学内容,具体的基础学习与其它的扩展知识内容,我会以链接的形式给出,若有兴趣可自行点击学习。 python基础知识教学 Pyth…

怎么压缩图片的体积大小,4款软件分享

怎么压缩图片的体积大小?因为在日常生活和工作中,我们常常会遇到需要压缩图片大小的情况。图片的大小是由像素点数量和每个像素的颜色深度共同决定的,一般来说,像素点数量越多,每个像素的颜色深度越高,图片…

四百元以内哪种耳机音质好?2023便宜音质好的蓝牙耳机推荐

现如今,蓝牙耳机的发展速度越来越快,不少人对于其音质方面的要求也越来越高。最近看到很多人问,有没有便宜音质又好的蓝牙耳机?针对这个问题,我来给大家推荐几款便宜音质好的蓝牙耳机,一起来看看吧。 一、…

怎么远程控制电脑

为什么要从另一台电脑远程控制电脑? 如今,Splashtop已广泛应用于各个领域。 在很多情况下,您需要从另一台远程电脑控制一台电脑。 这里演示了两个例子: 1:当您不在同一楼层时,您的同事需要您的帮助来解决…

阿里云张献涛:云原生计算基础设施助力汽车行业数字化升级

2023 年阿里云峰会北京站《云上智能汽车》论坛,阿里云智能基础产品部副总裁、阿里云智能弹性计算 & 无影产品线总经理张献涛,发表了《云原生计算基础设施助力汽车行业数字化升级》的主题演讲。 当前,汽车行业的数字化浪潮已经渗透到汽车设…

System V 共享内存

System V 共享内存 共享内存是什么如何使用共享内存ftokshmgetshmatshmdtshmctl 共享内存的原理共享内存实现两个进程间通信共享内存的特点共享内存与管道配合使用两个进程间通信多个进程间通信 共享内存是什么 🚀共享内存是最快的IPC形式。一旦这样的内存映射到共…

【产品应用】一体化步进伺服电机在高速异形插件机的应用

随着科技的不断发展,自动化生产设备在各个行业中得到了广泛的应用。高速异形插件机作为自动化生产设备中的一种,其核心部件之一就是一体化步进伺服电机。本文将详细介绍一体化步进伺服电机在高速异形插件机中的应用。 01.设备简介 高速异形插件机是一种…

我们为什么要写作?

为什么要写书是一个很难回答的问题,因为从不同的角度,会有不同的答案。 最近ChatGPT很火!诸事不决,先问问ChatGPT,看看它是怎么回答的。 ChatGPT给出的答案还是比较全,虽然没有“一本正经的胡说八道”&…

PCB高频电路设计中的差分信号设计

目录 1、差分信号的定义 2、如何布置差分线路? 3、微带线和带状线的概念 4、布线中常用的匹配方法 1、差分信号的定义 什么是差分布线:差分布线主要是区别传统的信号线对应一根地线的信号传输方式,差分信号传输主要是两条线上都有信号传…

基本数据类型和引用数据类型的存储区别?

目录 1、存储位置的区别 2、变量赋值时的区别 ① 基本数据类型 ② 引用数据类型 3、小结 ① 声明变量时不同的内存地址分配 ② 不同的类型数据导致赋值变量时的不同 1、存储位置的区别 基本数据类型和引用数据类型存储在内存中的位置不同: ① 基本数据类型存…

20230420 | 977. 有序数组的平方、 209. 长度最小的子数组、59. 螺旋矩阵 II

1、977. 有序数组的平方 方法1&#xff1a;使用暴力法&#xff0c;一遍for&#xff0c;一次排序。这个时间复杂度是 O(n nlogn)&#xff0c; 可以说是O(nlogn)的时间复杂度。 class Solution {public int[] sortedSquares(int[] nums) {//先计算出平方for(int i0;i<nums.le…

Vulnhub项目:JANGOW 1.0.1

靶机地址&#xff1a;Jangow: 1.0.1 ~ VulnHub 渗透过程&#xff1a; kali ip&#xff1a;192.168.56.104&#xff0c;使用arp-scan -l查看到靶机ip192.168.56.118 对靶机进行端口探测&#xff0c;发现了21、80端口 访问80端口&#xff0c;发现site目录 点击进去后&#xff0…

HIVE SQL 进行 Join 和 group by的具体原理及分区方式

HIVE SQL 实现Join和group by 具体原理 1、JOIN 在map的输出value中为不同表的数据打上tag标记&#xff0c;在reduce阶段根据tag判断数据来源。MapReduce的过程如下&#xff1a; 2、 GROUP BY HIVE SQL 实现Join和group by 的分区原理 1、JOIN 在join操作中&#xff0c;两个…

【Java】哔哩哔哩编程题练习

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 每日随心练&#xff0c;望各位大佬喜欢&#xff0c;做法有很多种&#xff0c;以下是我个人的想法 目录 一、复数乘法 二、一年中的第几天 三、k个一组翻转链表 一、复数乘法 输入两个表示复…

电路中电容的作用

总体目录 电源设计中常见电容常见电容作用降压滤波高通滤波平滑输出电压 延时耦合去耦/退耦旁路 不常用电容作用调谐电容衬垫电容补偿电容中和电容稳频电容定时电容加速电容启动电容运转电容 电源设计中常见电容 安规电容 常见电容作用 https://www.bilibili.com/video/BV…

【K8S系列】深入解析控制器

目录 序言 1 基础介绍 1.1 前情提要 1.2 Kube-controller-manager介绍 1.3 控制器类型 2 使用介绍 2.1 控制循环 2.2 Deployment控制器 实际状态&#xff1a; 期望状态&#xff1a; PodTemplate&#xff1a; 3 总结 4 投票 序言 在你想要放弃的时候&#xff0c;想…

常见的上采样操作以及其Pytorch实现

文章目录 常见的上采样操作以及其Pytorch实现一、[插值](https://www.cnblogs.com/zhaozhibo/p/15024928.html)1.最近邻插值2.双线性插值3.双三次插值 二、反卷积三、sub-pixel Convolution四、其它方法1.[superpoint](https://arxiv.org/abs/1911.11763)使用方法2.待补充 常见…

Word 设置标题编号

用到了多级列表&#xff0c;所谓多级列表&#xff0c;就是为段落标上编号&#xff0c;并不一定就要对文字使用&#xff0c; 教程参考自Word 多级列表编号方法总结&#xff08;二&#xff09;——自定义编号 - 知乎 直接看我的就好了 假设我们有一个需求 类似于这样的三级标题…

【SpringBoot】面试必杀技-泰山陨石坠,SpringBoot中主启动类的run方法启动流程是什么?

开头导语由Chatgpt完成 当今互联网行业中&#xff0c;Java后端开发岗位的竞争异常激烈&#xff0c;对于面试者来说&#xff0c;掌握一些技巧和知识点将有助于脱颖而出。而对于SpringBoot框架的使用和运行机制&#xff0c;更是Java后端开发岗位中不可或缺的技能点之一。在Spring…

Python里的元组、列表和字典区别

列表&#xff1a;可更改、有序、可重复、元素可以是任何对象 列表示例&#xff1a;[1,a,[2,3]] 元组&#xff1a;不可更改、有序、可重复、元素可以是任何对象 元组示例&#xff1a;(b,1,[2,3]) 字典&#xff1a;可更改、无序、键不可重复、键不可变、值可以是任何对象&…