嵌入式系统移植-04Linux内核分析(Linux内核基本概念,Linux内核启动分析,Linux内核调试方法)

文章目录

  • Linux内核基本概念
    • Linux内核
    • 主流的 Linux 发行版
    • Linux 内核的特性
    • Linux内核版本
    • Linux内核子系统
    • Linux内核模块结构图
    • linux内核编译(移植好的)
      • 编译内核 make uImage
      • 编译设备树 make dtbs
      • Linux内核代码结构(1)
      • Linux系统源代码目录结构(2)
  • Linux内核启动分析
    • 嵌入式系统启动信息分析
      • u-boot启动阶段
      • linux内核启动阶段
      • 根文件系统阶段(可运行应用程序)
    • 嵌入式系统 启动流程
    • 内核启动流程
  • Linux内核调试方法
    • 内核调试方法1:点灯法
    • 内核调试方法 2:printk打印输出信息
      • 打印函数
      • 打印级别
      • 通过proc在运行时查看和修改日志级别
    • 内核调试方法 3: OOP内核异常信息
      • 制造错误
      • 运行该内核报错
      • 找出错位置(arm-none-linux-gnueabi-addr2line)

Linux内核基本概念

Linux内核

  • 从技术上说 linux 是一个内核
  • “内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。
  • 通常我们使用的 linux 系统是一个集 linux 内核、工具集、各种库、桌面管理器、应用程序等一体的一个发布包 (发行版)‏

主流的 Linux 发行版

  • Debian GNU/Linux
  • Red Hat Linux
  • Fedora Core
  • Ubuntu Linux
  • SUSE Linux
  • Gentoo Linux
  • Asianux
  • Slackware Linux
  • Turbo Linux
  • CentOS

Linux 内核的特性

  • 免费开源
  • 可以移植,支持的硬件平台广泛
    arm, i386, m68k, m32r,m68knommu, mips, ppc, s390, sh, sparc
  • 高可扩展性
  • 可剪裁、可扩展,可以运行在大型主机,也可以运行在个人计算机上
  • 高可靠性、稳定性
  • 稳定性是linux鲜明特点,安装了linux系统的主机,
    连续运行一年不宕机是很平常的事情
  • 超强的网络功能
  • 真正的多任务,多用户系统
  • 模块化设计
  • 模块可以动态加载,卸载,可以减少系统体积,同时可以用来解决冲突问题,模块调试

Linux内核版本

目前linux系统采用 A.B.C.D 的版本号管理方式

  • A 表示linux的主版本号
  • B 表示linux的次版本号,B 为偶数表示稳定版本,奇数表示开发中的版本
  • C 表示linux的发行版本号
  • D 表示更新版本号
    主版本(X.Y)
    1.0 2.0 2.2 2.4 2.6 3.x

Linux内核子系统

  • 进程管理
  • 内存管理
  • 文件系统
  • 网络协议
  • 设备管理

linux系统不是正真的实时系统(采用时间片轮转的方式做的)
美国军方的Vxwork是正真的实时系统(中断抢占)

Linux内核模块结构图

在这里插入图片描述

应用访问内核要通过系统调用
内核访问硬件要通过映射

linux内核编译(移植好的)

编译内核 make uImage

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”是最新的。
CALL    scripts/checksyscalls.sh
CHK     include/generated/compile.h
Kernel: arch/arm/boot/Image is ready
Kernel: arch/arm/boot/zImage is ready
Image arch/arm/boot/uImage is ready
linux@linux:~/linux-3.14-fs4412$ 

编译设备树 make dtbs

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内核代码结构(1)

在这里插入图片描述

Linux系统源代码目录结构(2)

在这里插入图片描述

Linux内核启动分析

嵌入式系统启动信息分析

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

嵌入式系统 启动流程

在这里插入图片描述

//阶段一(汇编) 
设置为SVC模式,关闭中断,MMU,看门狗
基本硬件设备初始化  //初始化时钟,串口,flash,内存    
自搬移到内存          
设置好栈 跳转到C阶段
//阶段二(C语言)
大部分硬件初始化
搬移内核到 内存
运行内核

内核启动流程

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)
在这里插入图片描述

Linux内核调试方法

内核调试方法1:点灯法

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]

内核调试方法 2:printk打印输出信息

打印函数

puts   (内核解压前)
printascii  (console初始化前)
printk (内核解压后,信息输出显示是在 console 初始化之后)

打印级别

#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”);

通过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: OOP内核异常信息

制造错误

修改drivers/char/fs4412_led_drv.c
在s5pv210_led_init函数中int  ret=0;下增加下面语句: int *ptr  =  NULL; *ptr  = 0xff;

运行该内核报错

[    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 : []    lr : []    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)

找出错位置(arm-none-linux-gnueabi-addr2line)

根据PC is at s5pv210_led_init+0x18/0x180 知道出错的函数是s5pv210_led_init
根据pc : []  知道出错的位置
#arm-none-linux-gnueabi-addr2line c024225c -e vmlinux -f   在源码中会显示具体出错的位置

你可能感兴趣的:(嵌入式系统移植)