文章目录
1,基本概念
1.1,Linux内核
从技术上说 linux 是一个内核
“内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。
通常我们使用的 linux 系统是一个集 linux 内核、工具集、各种库、桌面管理器、应用程序等一体的一个发布包 (发行版)
1.2,主流的 Linux 发行版
Debian GNU/Linux
Red Hat Linux
Fedora Core
Ubuntu Linux
SUSE Linux
Gentoo Linux
Asianux
Slackware Linux
Turbo Linux
CentOS
1.3,Linux 内核的特性
免费开源
可以移植,支持的硬件平台广泛
arm, i386, m68k, m32r,m68knommu, mips, ppc, s390, sh, sparc
高可扩展性
可剪裁、可扩展,可以运行在大型主机,也可以运行在个人计算机上
高可靠性、稳定性
稳定性是linux鲜明特点,安装了linux系统的主机,
连续运行一年不宕机是很平常的事情
超强的网络功能
真正的多任务,多用户系统
模块化设计
模块可以动态加载,卸载,可以减少系统体积,同时可以用来解决冲突问题,模块调试
1.4,Linux内核版本
目前linux系统采用 A.B.C.D 的版本号管理方式
A 表示linux的主版本号
B 表示linux的次版本号,B 为偶数表示稳定版本,奇数表示开发中的版本(下载B 为偶数的版本)
C 表示linux的发行版本号
D 表示更新版本号
主版本(X.Y)
1.0 2.0 2.2 2.4 2.6 3.x
1.5,Linux内核子系统
进程管理
内存管理
文件系统
网络协议
设备管理
- linux系统不是正真的实时系统(采用时间片轮转的方式做的)
- 美国军方的Vxwork是正真的实时系统(中断抢占)
1.6,Linux内核模块结构图
- 应用访问内核要通过系统调用
- 内核访问硬件要通过映射
1.7,linux内核编译(移植好的)
1.7.1,拷贝到linux并解压,然后编译
linux@linux:~$ cp /mnt/hgfs/Linuxsharexiaomei/linux-3.14-fs4412.tar.xz
linux@linux:~$ tar -vxf linux-3.14-fs4412.tar.xz
linux@linux:~/linux-3.14-fs4412$ ls
arch cd crypto firmware include Kbuild lib mm README scripts tools
block COPYING Documentation fs init Kconfig MAINTAINERS Module.symvers REPORTING-BUGS security usr
build.sh CREDITS drivers fs4412_defconfig ipc kernel Makefile net samples sound virt
linux@linux:~/linux-3.14-fs4412$ make uImage
1.7.2,linux内核编编译出错make[1]: `include/generated/mach-types.h’ is up to date.
linux@linux:~/linux-3.14-fs4412$ make uImage
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h' is up to date.
CALL scripts/checksyscalls.sh
GEN scripts/mod/devicetable-offsets.h
HOSTCC scripts/mod/file2alias.o
scripts/basic/fixdep: 1: scripts/basic/fixdep: Syntax error: "(" unexpected
make[2]: *** [scripts/mod/file2alias.o] Error 2
make[1]: *** [scripts/mod] Error 2
make: *** [scripts] Error 2
1.7.2.1,解决方案
linux@linux:~/linux-3.14-fs4412$ make clean
linux@linux:~/linux-3.14-fs4412$ make uImage
1.7.3,linux内核编译出错"mkimage" command not found - U-Boot images will not be built
SHIPPED arch/arm/boot/compressed/bswapsdi2.S
AS arch/arm/boot/compressed/bswapsdi2.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
UIMAGE arch/arm/boot/uImage
"mkimage" command not found - U-Boot images will not be built
make[1]: *** [arch/arm/boot/uImage] Error 1
make: *** [uImage] Error 2
1.7.3.1,解决方案
linux@linux:~/linux-3.14-fs4412$ sudo apt-get install uboot-mkimage
[sudo] password for linux:
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package uboot-mkimage is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
u-boot-tools
E: Package 'uboot-mkimage' has no installation candidate
linux@linux:~/linux-3.14-fs4412$ sudo apt-get install u-boot-tools
1.7.4,编译成功
Image Name: Linux-3.14.0
Created: Fri Jan 11 19:41:27 2019
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3014944 Bytes = 2944.28 kB = 2.88 MB
Load Address: 40008000
Entry Point: 40008000
Image arch/arm/boot/uImage is ready
1.7.5,测试
1.7.5.1,备份原有的,拷贝新编译的
linux@linux:~/linux-3.14-fs4412$ mv /tftpboot/uImage /tftpboot/uImage.ok
linux@linux:~/linux-3.14-fs4412$ cp arch/arm/boot/uImage /tftpboot/
1.7.5.2,开发板重新上电,在串口终端中,查看启动信息
成功启动
1.8,编译设备树(设备树是3.14内核之后特有的)
1.8.1,编译设备树
linux@linux:~/linux-3.14-fs4412$ make dtbs
DTC arch/arm/boot/dts/exynos4210-origen.dtb
DTC arch/arm/boot/dts/exynos4210-smdkv310.dtb
DTC arch/arm/boot/dts/exynos4210-trats.dtb
DTC arch/arm/boot/dts/exynos4210-universal_c210.dtb
DTC arch/arm/boot/dts/exynos4412-odroidx.dtb
DTC arch/arm/boot/dts/exynos4412-origen.dtb
DTC arch/arm/boot/dts/exynos4412-fs4412.dtb
DTC arch/arm/boot/dts/exynos4412-smdk4412.dtb
DTC arch/arm/boot/dts/exynos4412-tiny4412.dtb
DTC arch/arm/boot/dts/exynos4412-trats2.dtb
DTC arch/arm/boot/dts/exynos5250-arndale.dtb
DTC arch/arm/boot/dts/exynos5250-smdk5250.dtb
DTC arch/arm/boot/dts/exynos5250-snow.dtb
DTC arch/arm/boot/dts/exynos5420-arndale-octa.dtb
DTC arch/arm/boot/dts/exynos5420-smdk5420.dtb
DTC arch/arm/boot/dts/exynos5440-sd5v1.dtb
DTC arch/arm/boot/dts/exynos5440-ssdk5440.dtb
linux@linux:~/linux-3.14-fs4412$
1.8.2,测试
1.8.2.1,备份原有的,拷贝需要的
linux@linux:~/linux-3.14-fs4412$ mv /tftpboot/exynos4412-fs4412.dtb /tftpboot/exynos4412-fs4412.dtb.ok
linux@linux:~/linux-3.14-fs4412$ cp arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot/
linux@linux:~/linux-3.14-fs4412$ cd /tftpboot/
linux@linux:/tftpboot$ ls
exynos4412-fs4412.dtb exynos4412-fs4412.dtb.ok uImage uImage.ok
1.8.2.2,开发板重新上电,观察启动信息
1.9,Linux内核代码结构
目录 | 简介 |
---|---|
kernel/ | Linux 内核管理核心源码 内核核心调度算法 |
arch/ arch/arm/mach-exynos | arch/目录 存放体系结构、平台相关代码(如arm系列,powerpc系列等) arch/arm/目录存放arm系列不同机器型号的代码(自己新开发了一个机器,就要新增加一个,比如:arch/arm/mach-exynos,就是4412开发板的) |
drivers/ | 所有的驱动代码 (drivers/usb/, etc.) 专门和硬件打交道的代码 |
include/ include/asm- | 内核头文件 体系结构相关头文件 Linux内核基本的头文件(保留类型和配置) |
include/linux/lib | 混合库代码 (zlib, crc32...) |
fs/ | 文件系统代码 (fs/ext3/, etc.) |
ipc/ | 进程通讯相关代码 |
mm/ | 内存管理代码 |
net/ | 网络协议代码 |
2,启动分析
2.1,嵌入式系统启动信息分析
- u-boot启动阶段
U-Boot 2013.01 (Aug 24 2014 - 12:01:19) for FS4412
CPU: Exynos4412@1000MHz
Board: FS4412
DRAM: 1 GiB
……Loading: * ######################
Starting kernel ...
- linux内核启动阶段
Booting Linux on physical CPU 0xa00
Linux version 3.14.0 (david@ubuntu)
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
Machine model: Insignal Origen evaluation board based on Exynos4412
IP-Config: Complete:
VFS: Mounted root (nfs filesystem) on device 0:10
- 根文件系统阶段(可运行应用程序)
[root@farsight ]# ls
a.out dev lib mnt root sys usr
bin etc linuxrc proc sbin tmp va
2.2,嵌入式系统 启动流程
//阶段一(汇编)
设置为SVC模式,关闭中断,MMU,看门狗
基本硬件设备初始化 //初始化时钟,串口,flash,内存
自搬移到内存
设置好栈 跳转到C阶段
//阶段二(C语言)
大部分硬件初始化
搬移内核到 内存
运行内核
2.3,内核启动流程
a. 自解压内核 decompess (arch/arm/boot/compressed/head.S) | |
b. 运行内核汇编部分 head.S 入口stext (arch/arm/kernel/head.S) 检测合法性(CPU 类型,机器类型) | |
c. 运行内核C部分 start_kernel (init/main.c) CPU,机器参数的安装 setup_arch 中断,定时,终端,内存等最基本的初始化 创建核心进程 kernel_init运行,启动多任务调度 | |
d. 挂载rootfs(根文件系统) | |
e. 运行第一个应用程序init (一般是 linuxrc) |
3,调试方法
3.1,点灯法
启动过程中,串口无打印信息,可以将最简单的LED灯的汇编代码,加入到想要分析的文件的,相应的代码位置,通过看灯有没有被点亮,从而判断程序有没有执行到这里
ldr r0, =0x11000c40 @GPK2_7 led2
ldr r1, [r0]
bic r1, r1, #0xf0000000
orr r1, r1, #0x10000000
str r1, [r0]
ldr r0, =0x11000c44
mov r1,#0xff
str r1, [r0]
3.2,printk打印输出信息
3.2.1,三个打印函数
puts (内核解压前用)
printascii (内核解压后,console(串口)初始化前)
printk (内核解压后,信息输出显示是在 console 初始化之后)
3.2.2,打印级别:
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>” /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages
printk( KERN_INFO “ \n INFO Level \n”);
3.2.3,通过proc在运行时查看和修改日志级别
cat /proc/sys/kernel/printk 显示 4 4 1 7
echo “7 4 1 7” > /proc/sys/kernel/printk 后
cat /proc/sys/kernel/printk 显示7 4 1 7
3.2.4,例
3.2.4.1,在init/main.c中加入printk()打印信息
3.2.4.2,编译uImage,并拷贝至/tftpboot/目录
linux@linux:~/linux-3.14-fs4412$ make uImage
linux@linux:~/linux-3.14-fs4412$ cp arch/arm/boot/uImage /tftpboot/
3.2.4.3,开发板上电重启,查看打印信息
3.3,OOP内核异常信息
3.3.1,制造错误
修改drivers/char/fs4412_led_drv.c
在s5pv210_led_init函数中int ret=0;下增加下面语句: int *ptr = NULL; *ptr = 0xff;
3.3.2,运行该内核报错
[ 1.165000] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 1.170000] pgd = c0004000
[ 1.175000] [00000000] *pgd=00000000
[ 1.175000] Internal error: Oops: 805 [#1] PREEMPT SMP ARM
[ 1.180000] Modules linked in:
[ 1.185000] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.14.0 #25
[ 1.190000] task: ee8a0000 ti: ee8a4000 task.ti: ee8a4000
[ 1.195000] PC is at s5pv210_led_init+0x18/0x180
[ 1.200000] LR is at do_one_initcall+0x30/0x144
[ 1.205000] pc : [<c024225c>] lr : [<c00087b4>] psr: 60000153
[ 1.205000] sp : ee8a5ef8 ip : c059afac fp : 00000000
[ 1.215000] r10: c052d4fc r9 : c0564b80 r8 : c0242244
[ 1.220000] r7 : c05a3400 r6 : c055134c r5 : 00000000 r4 : ee8a4000
[ 1.230000] r3 : 00000055 r2 : c04c0430 r1 : 00000001 r0 : 1f400000
[ 1.235000] Flags: nZCv IRQs on FIQs off Mode SVC_32 ISA ARM Segment kernel
[ 1.245000] Control: 10c5387d Table: 4000404a DAC: 00000015
[ 1.250000] Process swapper/0 (pid: 1, stack limit = 0xee8a4240)
[ 1.255000] Stack: (0xee8a5ef8 to 0xee8a6000)
3.3.3,找出错位置
根据PC is at s5pv210_led_init+0x18/0x180 知道出错的函数是s5pv210_led_init
根据pc : [<c024225c>] 知道出错的位置
#arm-none-linux-gnueabi-addr2line c024225c -e vmlinux -f 在源码中会显示具体出错的位置
3.3.4,例
3.3.4.1,制造错误
3.3.4.2,编译
查看编译信息,发现没有编译drivers/char/fs4412_led_drv.c
3.3.4.3,临时修改drivers/char/Makefile
3.3.4.4,再次编译,如果成功,拷贝至/tftpboot/目录
3.3.4.5,开发板上电重启,查看串口终端打印信息
3.3.4.6,如果还是不能确定具体位置,可以通过arm-none-linux-gnueabi-addr2line反向定位出错位置
linux@linux:~/linux-3.14-fs4412$ arm-none-linux-gnueabi-addr2line c024225c -e vmlinux -f
s5pv210_led_init
/home/linux/linux-3.14-fs4412/drivers/char/fs4412_led_drv.c:71
在/home/linux/linux-3.14-fs4412/drivers/char/fs4412_led_drv.c文件的第71行