抚顺清原网站建设招聘,湖南营销型网站建设报价,医疗类网站建设,福建省教师空间建设网站目录
1 问题一#xff1a;内核移植时MTD分区问题
2 问题二#xff1a;uboot的MTDPARTS_DEFAULT定义的MTD分区#xff0c;bootargs中的文件系统分区#xff0c;内核的mtd_partition smdk_default_nand_part定义的分区#xff0c;三者要对应起来
3 问题三#xff1a;ubo…目录
1 问题一内核移植时MTD分区问题
2 问题二uboot的MTDPARTS_DEFAULT定义的MTD分区bootargs中的文件系统分区内核的mtd_partition smdk_default_nand_part定义的分区三者要对应起来
3 问题三uboot不再传tag地址了那内核怎么知道bootargs的
4 问题四内核是怎么解析uboot传过来的tags地址或者设备树地址的
5 问题五linux内核官网的疑问
6 下载内核源码
7 安装交叉编译工具链
8 修改顶层Makefile
9 修改时钟频率
10 修改MTD分区
11 关闭软件ECC校验
12 支持yaffs文件系统
13 支持设备树
14 配置内核
14.1 make s3c2410_defconfig
14.2 make menuconfig
15 编译内核和设备树文件
16 下载内核
17 参考文献 在移植linux内核之前我先把韦老师的开发手册过了一遍发现了好几个不太明白的问题先把这些问题都弄明白再移植。
1 问题一内核移植时MTD分区问题
Linux开发手册上内核移植MTD分区那里0地址保存的竟然是kernel我记得之前0地址不都是保存的bootloader吗 看到这里不理解如果0地址保存的是kernel那不是把bootloader覆盖了吗搞不懂一直没弄懂怎么回事直到我往前翻看到了uboot移植的介绍那里我发现了这个
原来韦老师是把bootloader放到了norflash里面怪不得nandflash的0就直接放kernel因为我是先移植内核先看的内核移植部分所以没看到这里。 不过我移植内核的时候不会按老师这种方式做我还是nandflash的0地址先放bootloader。
2 问题二uboot的MTDPARTS_DEFAULT定义的MTD分区bootargs中的文件系统分区内核的mtd_partition smdk_default_nand_part定义的分区三者要对应起来
这个是什么意思呢就是uboot中有分区定义如下
#define MTDIDS_DEFAULT nand0nandflash0
#define MTDPARTS_DEFAULT mtdpartsnandflash0:256k0(bootloader), \128k(device_tree), \128k(params), \4m(kernel), \-(root)
这里uboot定义的是前面256k存放bootloader然后接下来128k存放的是设备树然后接下来128k存放的是参数然后接下来4m保存的是内核后面的是文件系统。
那么bootargs里面root赋值就要是 root/dev/mtdblock4
bootargs noinitrd root/dev/mtdblock4 rw init/linuxrc consolettySAC0,115200;
然后内核中 就要这么定义
static struct mtd_partition smdk_default_nand_part[] {[0] {.name bootloader,.size SZ_256K,.offset 0,},[1] {.name device_tree,.offset MTDPART_OFS_APPEND,.size SZ_128K,},[2] {.name params,.offset MTDPART_OFS_APPEND,.size SZ_128K,},[3] {.name kernel,.offset MTDPART_OFS_APPEND,.size SZ_4M,},[4] {.name rootfs,.offset MTDPART_OFS_APPEND,.size MTDPART_SIZ_FULL,}};
3 问题三uboot不再传tag地址了那内核怎么知道bootargs的
我看了韦老师的设备树里面用的uboot他那里的uboot在调用theKernel的时候第三个参数传进来的是设备树文件的地址并没有传启动参数的保存地址也就是tag地址那么内核怎么得到bootargs那些参数呢这个问题也没想明白在技术群里问了下他们说可能是启动参数直接放设备树里面了于是我去看了下设备树在设备树中找到了下面一行 chosen {bootargs noinitrd root/dev/mtdblock4 rw init/linuxrc consolettySAC0,115200;};
原来是把启动参数放到设备树里面了。
但是看了下新版的uboot源码其实新版里面是可以传tag也可以传设备树文件地址。新版源码如下图 而韦老师是因为用的老版的uboot但是又想在老板uboot里面支持设备树所以韦老师修改如下 theKernel (void (*)(int, int, uint))ntohl(hdr-ih_ep); /* 100ask for device tree, no initrd image used */if (argc 4) {of_flat_tree (char *) simple_strtoul(argv[3], NULL, 16);if (be32_to_cpu(*(ulong *)of_flat_tree) OF_DT_HEADER) {printf (\nStarting kernel with device tree at 0x%x...\n\n, of_flat_tree);cleanup_before_linux (); theKernel (0, bd-bi_arch_number, of_flat_tree);} else {printf(Bad magic of device tree at 0x%x!\n\n, of_flat_tree);}}如果参数等于4就把设备树地址传给内核这是因为使用设备树时候我们输入的bootm命令是4个参数。
bootm uImage_addr // 无设备树,bootm 0x30007FC0
bootm uImage_addr initrd_addr dtb_addr // 有设备树另外还一个问题就是在使用设备树的时候如果也还是传输过来了bootargs那么bootargs的优先级更高,
从设备树(dtb格式数据)中解析出bootargs_dts bootargs_正在起飞的蜗牛的博客-CSDN博客
(1)内核启动参数bootargs保存在设备树的chosen节点的bootargs属性 (2)bootargs数据可以是在dts源文件中定义也可以是uboot启动内核时传递给内核 (3)优先级uboot传递的bootargs参数优先级高于dts中定义的bootargs (4)如果是uboot传递的bootargs在内核解压缩阶段就会调用atags_to_fdt()函数将tag中的bootargs参数转换成dtb的格式写进dtb数据中
这时候内核用的应该是zImage-dtb格式vmlinuz/vmlinux、Image、zImage与uImage的区别_vmlinux和uimage_正在起飞的蜗牛的博客-CSDN博客
4 问题四内核是怎么解析uboot传过来的tags地址或者设备树地址的
之前老的uboot里面调用theKernel函数的时候第三参数是tag地址也就是bootargs的那些地址但是新版的uboot里面调用theKernel函数启动内核的时候第三个参数可能是tags地址也可能是设备树地址那么内核肯定是两种方式都支持那么是怎么支持的这个我去看了下这一块的内核源码先不看head.S了直接去看start_kernel函数
asmlinkage __visible void __init start_kernel(void)
{char *command_line;char *after_dashes;set_task_stack_end_magic(init_task);smp_setup_processor_id();debug_objects_early_init();cgroup_init_early();local_irq_disable();early_boot_irqs_disabled true;/** Interrupts are still disabled. Do necessary setups, then* enable them.*/boot_cpu_init();page_address_init();pr_notice(%s, linux_banner);setup_arch(command_line);........//其他代码
然后看这里面的setup_arch函数在arch/arm/kernel/setup.c里面
void __init setup_arch(char **cmdline_p)
{const struct machine_desc *mdesc;setup_processor();/*这个__atags_pointer就是uboot穿进来的第三个参数也就是tag地址或者设备树地址然后这个setup_machine_fdt里面是对设备树是否有效*/mdesc setup_machine_fdt(__atags_pointer);if (!mdesc)mdesc setup_machine_tags(__atags_pointer, __machine_arch_type);//上面判断设备树无效那说明穿进来的就是tag地址了。那么解析tag。if (!mdesc) {early_print(\nError: invalid dtb and unrecognized/unsupported machine ID\n);early_print( r10x%08x, r20x%08x\n, __machine_arch_type,__atags_pointer);if (__atags_pointer)early_print( r2[]%*ph\n, 16,phys_to_virt(__atags_pointer));dump_machine_table();}machine_desc mdesc;
这里面首先是setup_machine_fdt函数在这个setup_machine_fdt函数里面调用early_init_dt_verify函数判断是否是有效的设备树然后再解析设备树。
/*** setup_machine_fdt - Machine setup when an dtb was passed to the kernel* dt_phys: physical address of dt blob** If a dtb was passed to the kernel in r2, then use it to choose the* correct machine_desc and to setup the system.*/
const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
{const struct machine_desc *mdesc, *mdesc_best NULL;#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)DT_MACHINE_START(GENERIC_DT, Generic DT based system).l2c_aux_val 0x0,.l2c_aux_mask ~0x0,MACHINE_ENDmdesc_best __mach_desc_GENERIC_DT;
#endifif (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))//判断是否有效的dtbreturn NULL;mdesc of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);if (!mdesc) {const char *prop;int size;unsigned long dt_root;early_print(\nError: unrecognized/unsupported device tree compatible list:\n[ );dt_root of_get_flat_dt_root();prop of_get_flat_dt_prop(dt_root, compatible, size);while (size 0) {early_print(%s , prop);size - strlen(prop) 1;prop strlen(prop) 1;}early_print(]\n\n);dump_machine_table(); /* does not return */}/* We really dont want to do this, but sometimes firmware provides buggy data */if (mdesc-dt_fixup)mdesc-dt_fixup();early_init_dt_scan_nodes(); 如果early_init_dt_verify函数判断不是有效的设备树那么就调用setup_machine_tags函数把第三个参数当成tag地址来解析总结一下就是
setup_arch setup_machine_fdtif (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))//判断是否有效的dtbearly_init_dt_scan_nodes();mdesc setup_machine_tags(__atags_pointer, __machine_arch_type);前面的没成立那么说明传进来的不是设备树文件地址而是启动参数的tag地址那么这里是直接解析tag参数了
5 问题五linux内核官网的疑问
The Linux Kernel Archives 当我登录linux内核官网后这里tarball是下载源码然后后面我发现了两个东西patch和inc.patch然后我鼠标放到patch提示Download patch to previous mainline,然后鼠标放到inc.patch提示Download incremental patch搞不懂这两个有什么区别然后我下载inc.patch发现名字是这样的patch-5.10.169-170.xz那么这个应该是说5.10.169到5.10.170的补丁但是patch是啥在技术交流群里问了下别人跟我说linux的主版本号我还是不懂然后我去查了下linux版本号问题例如5.10.170.21吧5.10是主版本好170是次版本号然后21是扩展版本号所以这里的patchDownload patch to previous mainline意思是5.10.170针对5.10增加的补丁文件好懂了。
然后还一个就是官网主页只显示了几个内核版本其他版本在上面的那个HttpIndex of /pub/
6 下载内核源码
我去The Linux Kernel Archives 这里不下载最新的了就用4.19.275吧下载完之后用下面的命令解压。
xz -d linux-4.19.275.tar.xz
tar -xavf linux-4.19.275.tar
7 安装交叉编译工具链
这里用gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz直接解压然后设置环境变量就可以了安装完之后我想看一下是否安装成功了发现如下错误
arm-linux-gcc --version
/usr/local/arm/4.3.2/bin/arm-linux-gcc: line 3: /usr/local/arm/4.3.2/bin/arm-none-linux-gnueabi-gcc: No such file or directory
网上搜了下这是因为操作系统是64位的而交叉编译工具链是32位的所以需要安装下面的包兼容32位。
sudo apt-get install lib32z1
8 修改顶层Makefile
这里修改交叉编译工具链
#ARCH ? $(SUBARCH)ARCH ? arm
CROSS_COMPILE ? arm-linux-gnueabi-
9 修改时钟频率
arch/arm/mach-s3c24xx/mach-smdk2440.c中将时钟频率修改为12M
static void __init smdk2440_init_time(void)
{//s3c2440_init_clocks(16934400);s3c2440_init_clocks(12000000);samsung_timer_init();
}10 修改MTD分区
arch/arm/mach-s3c24xx/common-smdk.c文件中将代码
static struct mtd_partition smdk_default_nand_part[] {[0] {.name Boot Agent,.size SZ_16K,.offset 0,},[1] {.name S3C2410 flash partition 1,.offset 0,.size SZ_2M,},[2] {.name S3C2410 flash partition 2,.offset SZ_4M,.size SZ_4M,},[3] {.name S3C2410 flash partition 3,.offset SZ_8M,.size SZ_2M,},[4] {.name S3C2410 flash partition 4,.offset SZ_1M * 10,.size SZ_4M,},[5] {.name S3C2410 flash partition 5,.offset SZ_1M * 14,.size SZ_1M * 10,},[6] {.name S3C2410 flash partition 6,.offset SZ_1M * 24,.size SZ_1M * 24,},[7] {.name S3C2410 flash partition 7,.offset SZ_1M * 48,.size MTDPART_SIZ_FULL,}
};
修改为下面的代码
static struct mtd_partition smdk_default_nand_part[] {[0] {.name bootloader,.size SZ_256K,.offset 0,},[1] {.name device_tree,.offset MTDPART_OFS_APPEND,.size SZ_128K,},[2] {.name params,.offset MTDPART_OFS_APPEND,.size SZ_128K,},[3] {.name kernel,.offset MTDPART_OFS_APPEND,.size SZ_4M,},[4] {.name rootfs,.offset MTDPART_OFS_APPEND,.size MTDPART_SIZ_FULL,}};
11 关闭软件ECC校验
修改arch/arm/mach-s3c24xx/common-smdk.c文件 12 支持yaffs文件系统
Get Yaffs | Yaffs - A Flash File System for embedded use
yaffs官网上让用下面的命令下载
git clone git://www.aleph1.co.uk/yaffs2
然后需要运行文件系统里面的patch-ker.sh脚本文件先./patch-ker.sh看一下使用说明
./patch-ker.sh
usage: ./patch-ker.sh c/l m/s kernelpathif c/l is c, then copy. If l then linkif m/s is m, then use multi version code. If s then use single version code所以这里 13 支持设备树
这里移植内核的时候想把设备树也用上然后参考了韦东山老师的设备树教程以及彭东林老师的这个博客https://www.cnblogs.com/pengdonglin137/p/6241895.html
使用下面的设备树文件
// SPDX-License-Identifier: GPL-2.0
/** SAMSUNG SMDK2440 board device tree source** Copyright (c) 2018 weidongshanqq.com* dtc -I dtb -O dts -o jz2440.dts jz2440.dtb*/#define S3C2410_GPA(_nr) ((016) (_nr))
#define S3C2410_GPB(_nr) ((116) (_nr))
#define S3C2410_GPC(_nr) ((216) (_nr))
#define S3C2410_GPD(_nr) ((316) (_nr))
#define S3C2410_GPE(_nr) ((416) (_nr))
#define S3C2410_GPF(_nr) ((516) (_nr))
#define S3C2410_GPG(_nr) ((616) (_nr))
#define S3C2410_GPH(_nr) ((716) (_nr))
#define S3C2410_GPJ(_nr) ((816) (_nr))
#define S3C2410_GPK(_nr) ((916) (_nr))
#define S3C2410_GPL(_nr) ((1016) (_nr))
#define S3C2410_GPM(_nr) ((1116) (_nr))/dts-v1/;/ {model SMDK24440;compatible samsung,smdk2440;#address-cells 1;#size-cells 1;memory30000000 {device_type memory;reg 0x30000000 0x4000000;};
/*cpus {cpu {compatible arm,arm926ej-s;};};
*/ chosen {bootargs noinitrd root/dev/mtdblock4 rw init/linuxrc consolettySAC0,115200;};led {compatible jz2440_led;reg S3C2410_GPF(5) 1;};
};
将上述文件命名为jz2440.dts放到arm/boot/dts/jz2440.dts
那同时要修改设备树里面的Makefile增加 dtb-$(CONFIG_ARCH_S3C2440) jz2440.dtb 前面设备树文件中compatible samsung,smdk2440;
那么在内核arch/arm/mach-s3c24xx/mach-smdk2440.c文件中首先增加如下定义
14 配置内核
14.1 make s3c2410_defconfig
我们首先使用make s3c2410_defconfig生成.config然后再用make menuconfig图形化界面上微调。
make s3c2410_defconfig
然后发现报错 HOSTCC scripts/basic/fixdepHOSTCC scripts/kconfig/conf.oYACC scripts/kconfig/zconf.tab.c
/bin/sh: 1: bison: not found
scripts/Makefile.lib:196: recipe for target scripts/kconfig/zconf.tab.c failed
make[1]: *** [scripts/kconfig/zconf.tab.c] Error 127
Makefile:557: recipe for target s3c2410_defconfig failed
make: *** [s3c2410_defconfig] Error 2网上搜索发现用如下方法解决
sudo apt install bison flex
然后重新执行make s3c2410_defconfig发现生成了.config我们执行 make s3c2410_defconfig时所有配置项都被写到.config文件里面去了。 YACC scripts/kconfig/zconf.tab.cLEX scripts/kconfig/zconf.lex.cHOSTCC scripts/kconfig/zconf.tab.oHOSTLD scripts/kconfig/conf
#
# configuration written to .config
#14.2 make menuconfig
然后我们执行make menuconfigmake menuconfig其实会去读上面生成的.config文件然后会出现一个菜单供我们选择。
make menuconfig 这里加一个菜单使用说明改菜单截图自https://www.cnblogs.com/lifexy/p/7342031.html 这里首先要配置支持yaff2文件系统。
File systems --- [*] Miscellaneous filesystems ---* yaffs2 file system support
然后再Boot options里面发现设备树默认是选上的。
15 编译内核和设备树文件
配置完成之后用下面命令编译
make uImage -j8
报错 CALL scripts/checksyscalls.shCHK include/generated/compile.hKernel: arch/arm/boot/Image is readyKernel: arch/arm/boot/zImage is readyUIMAGE arch/arm/boot/uImage
mkimage command not found - U-Boot images will not be built
arch/arm/boot/Makefile:90: recipe for target arch/arm/boot/uImage failed
make[1]: *** [arch/arm/boot/uImage] Error 1
arch/arm/Makefile:336: recipe for target uImage failed
make: *** [uImage] Error 2说明缺少 mkimage 有两种解决办法
利用uboot生成mkimage工具然后拷贝到/usr/bin 目录下输入 sudo apt-get install u-boot-tools 命令在线安装
这里直接用
sudo apt-get install u-boot-tools
然后编译生成了uImage CALL scripts/checksyscalls.shCHK include/generated/compile.hKernel: arch/arm/boot/Image is readyKernel: arch/arm/boot/zImage is readyUIMAGE arch/arm/boot/uImage
Image Name: Linux-4.19.275
Created: Thu Mar 9 13:45:42 2023
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3661464 Bytes 3575.65 KiB 3.49 MiB
Load Address: 30108000
Entry Point: 30108000Kernel: arch/arm/boot/uImage is ready然后还要编译设备树文件
make dtbs
生成arch/arm/boot/dts/jz2440.dtb。
16 下载内核
然后把uImage下载到开发板中启动发现卡住了。。。。。 NAND read: device 0 offset 0x40000, size 0x20000Reading data from 0x5f800 -- 100% complete.131072 bytes read: OK
## Booting image at 30007fc0 ...Image Name: Linux-4.19.275Created: 2023-03-09 6:59:04 UTCImage Type: ARM Linux Kernel Image (uncompressed)Data Size: 3660816 Bytes 3.5 MBLoad Address: 30108000Entry Point: 30108000Verifying Checksum ... OK
OKStarting kernel with device tree at 0x32000000...我也不知道错在哪里了我去内核中的init/main.c中增加打印 然后重新make uImage -j8,把内核下载进去然后启动发现能打印出来 这说明内核已经到了start_kernel函数了那我再加打印试试 这样打印也看不出来啥问题网上其他人在2440上移植内核的时候看着都很顺利不过他们没移植设备树那我得问题很可能是移植设备树然后有个什么地方我没弄好我又回去去看了韦老师和彭东林老师的教程和博客。然后我发现了韦老师内核中有个这样的修改
上面那段英文注释翻译过来是目前有两种驱动程序可以为三星soc提供GPIO支持。对于支持设备树的平台使用了新的pinctrl-samsung驱动程序提供了GPIO和引脚控制接口。对于遗留(非dt)平台使用这个驱动程序。
因为韦老师用了设备树文件所以不注释掉的话检测到设备树文件后下面的那些初始化直接就不做了但是韦老师的设备树文件又非常简单不完整所以应该是内核少做了很多初始化工作我把我的内核源码中这一块也注释掉果然内核起来了。 内核起来了但是还有个错误这是文件系统的问题内核移植就先到这里了。
17 参考文献
TQ2440(S3C2440)移植Linux-4.0.1内核全过程_觉皇不秃头的博客-CSDN博客 讓TQ2440也用上設備樹1 S3C2440 移植最新5.2linux内核
Linux设备树学习(三)uboot和Linux中的设备树移植
JZ2440支持设备树(1)-添加设备树之后kernel的启动参数跟dts里面不一致
Mini2440之linux内核移植