嵌入式Linux(二十二)Linux内核分析及移植

1. 编译linux内核

  NXP从linux官网下载内核,然后移植到自己的CPU,我们的移植是基于NXP,再移植到自己的开发板。

制作一个sh:

#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

2. Linux工程目录分析

需要关注的文件夹和文件如下:

  1. arch目录:和架构有关,进行CPU的配置。
     arch/arm/configs:默认配置文件。
     arch/arm/boot/dts:设备树文件。
     arch/arm/boot:保存编译出的Image和zImage文件。
     arch/arm/mach-xxx:驱动和初始化文件。
  2. block目录:Linux的块设备目录,存放管理SD,EMMC等块设备的文件。
  3. crypto目录:加密文件crc,crc32,md4,hash等。
  4. Documentation目录:Linux相关文档。
  5. drivers目录:驱动目录文件。
  6. firmware目录:存放固件。
  7. fs目录:存放文件系统如fs/ext4等。
  8. include;init头文件目录;linux内核启动时初始化代码。
  9. ipc;kernel;lib;mm:进程间通信代码;内核代码;库;内存管理代码。
  10. net;samples;scripts网络相关代码;示例代码;脚本文件。
  11. security;sound;tools;usr:安全相关;音频相关;编译工具;initramfs有关。
  12. virt;.config;Kbuild;Kconfig:虚拟机相关;linux的最终配置信息;Makefile会读取;图形化界面配置文件
  13. Makefile

Linux顶层Makefile主要就是生成vmlinux并压缩成zImage。
关于几个编译出来的文件:
①vmlinux:最原始的内核文件,未压缩的。
②Image:Linux内核镜像文件,仅包含可执行的二进制数据。
③zImage:zImage是gzip压缩后的Image。
④uImage:老版本uboot专用的镜像文件。比zImage多一些头部信息。

3. Linux内核启动流程

查看linux内核的链接脚本文件arch/arm/kernel/vmlinux.lds:

ENTRY(stext)            /*指明Linux内核入口为stext*/

stext在arch/arm/kernel/head.S中,简单概括一下其流程:
①__lookup_processor_type:找到对应处理器的procinfo结构。
②__vet_atags:验证设备树的合法性。
③__create_page_tables:创建页表。
④__mmap_switched:调用start_kernel函数。
⑤__enable_mmu:使能MMU,执行__mmap_switched。

start_kernel函数最终调用了rest_init(init/main.c),简单流程概括为:
①rcu_scheduler_starting:启动RCU锁调度器。
②kernel_thread:创建kernel_init内核进程,PID=1。实现内核态到用户态的转变。
③kernel_thread:创建kthreadd内核进程,PID=2。负责进行所有内核进程的调度管理。
④cpu_startup_entry:进入idle(空闲)进程,PID=0。

ps -A         /*在linux终端输入该命令以查看当前所有进程(不显示内核态进程)*/

  Linux内核构建完成后挂载rootfs根文件系统,执行根文件系统中的init程序进入用户态。

4. Linux内核移植

4.1 根文件系统缺失错误

  根文件系统存放是有uboot的bootargs环境变量指定的。这里bootargs如下,根文件系统存储在/dev/mmcblk1p2也就是EMMC的分区2。

console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw

  实际做产品的话新硬件是没有对应的根文件系统的,在这之前linux内核没有rootfs,启动时会报根文件系统缺失错误。提示内核崩溃,VFS虚拟文件系统不能挂载根文件系统(内核依然是启动的)。

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

4.2 在Linux中添加自己的开发板

  编译了NXP的evk板子对应内核,可以在正点原子EMMC板上启动,所以基于NXP的imx_v7_mfg_config添加自己的开发板。

4.2.1 添加开发板默认配置文件和设备树文件

  复制imx_v7_mfg_config为imx_alientek_emmc_defconfig,做如下修改:注释掉“CONFIG_ARCH_MULTI_V6=y”。6ULL是V7架构,所以要屏蔽掉V6相关选项。
  复制imx6ull-14x14-evk.dts为imx6ull-alientek-emmc.dts,修改对应层级Makefile,在“dtb-
$(CONFIG_SOC_IMX6ULL)”配置项中加入imx6ull-alientek-emmc.dtb,确保dts可以编译为dtb。
  这里编译了一下,成功启动了linux,说明开发板添加上去了,但是还要修改一些配置。

4.2.2 CPU主频和网络驱动修改

4.2.2.1 CPU主频修改

启动linux内核并查看一下cpu信息,如下,MogoMIPS代表处理器性能:
嵌入式Linux(二十二)Linux内核分析及移植_第1张图片
上面看不到主频,进入一下目录中查看,CPU频率为792MHz。
在这里插入图片描述
使用如下命令查看CPU在各频率下的工作时长:
在这里插入图片描述
查看CPU调频策略,这里performance表示一直运行在最高频,但是实际开发中建议切换为ondemand模式,根据负载自动切换频率。
在这里插入图片描述

4.2.2.2 EMMC驱动修改

**1)使能8线EMMC驱动:**将imx6ull-alientek-emmc.dts中“&usdhc2”的内容修改为:

&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;
	no-1-8-v;
	status = "okay";
};

2)关闭EMMC 1.8V供电选项:
  正点原子emmc板EMMC工作电压为3.3V,所以要关闭1.8V选项避免驱动出现问题。在上面的“&usdhc2”加入“no-1-8-v;”

4.2.2.3 网络驱动修改

  NXP的板子和我们的板子不是一个PHY芯片,它将SR8201F需要的引脚给spi4用了,所以先在dts文件里去除相关配置。然后在dts的“iomuxc_snvs”节点里添加如下网络引脚复位信息。
嵌入式Linux(二十二)Linux内核分析及移植_第2张图片
  然后修改fec1和fec2节点的pinctrl-0属性,在里面加上&pinctrl_enetx_reset。接下来修改SR8201F的PHY地址,在fec1和2节点中添加以下内容:

phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;    /*ENET1为GPIO5_IO07,ENET2为08*/   /*低电平有效*/
phy-reset-duration = <200>;                      /*复位电平信号持续时间200ms*/

smsc,disable-energy-detect;           /*表明PHY芯片时SMSC公司的,内核就会找到相应驱动驱动LAN8720A*/

  在fec_main.c文件中的fec_reset_phy函数最后再加一句“msleep(200)”,因为复位结束后至少还要再过150ms才可以继续操作SR8201F。

测试:
linux启动后,输入ifconfig -a查看所有网卡。然后输入ifconfig eth0 up启动ENET2,有ip地址说明开启了。可以使用ifconfig eth0 xxx配置其ip地址。

你可能感兴趣的:(linux,运维,服务器)