• 第4天--linux内核学习


    驱动使用方式
    1、编译到内核中 * make uImage
    进入到系统后
    mknod /dev/led c 500 0 创建设备节点

    2、编译为模块 M make module
    进入到系统后
    mknod /dev/led c 500 0 创建设备节点
    insmod fs4412_led_drv.ko(驱动可执行程序) 加载驱动

    uImage的编译
    1、步骤
    make uImage -jNUM NUM = 处理器数量*处理器核心数

    2、流程
    进入顶层目录下的Makefile
    找不到uImage 就去找include
    504 include $(srctree)/arch/$(SRCARCH)/Makefile ==> arch/arm/Makefile
    203 SRCARCH := $(ARCH) =arm

    进入arch/arm/Makefile
    299 BOOT_TARGETS = zImage Image xipImage bootpImage uImage

    304 $(BOOT_TARGETS): vmlinux
    305 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ ==> arch/arm/boot/uImage

    make -p生成工程目录下的全局变量
    62 Q = @ 272 MAKE = make
    Makefile中 @make $(build) make -C build的路径 执行指定路径下的Makefile
    291 boot := arch/arm/boot

    233 MACHINE := arch/arm/mach-$(word 1,$(machine-y))/
    155 machine-$(CONFIG_ARCH_EXYNOS) += exynos (在配置文件.config中)
    MACHINE=arch/arm/mach-exynos

    make -C arch/arm/boot MACHINE=arch/arm/mach-exynos arch/arm/boot/uImage

    进入arch/arm/boot/Makefile中

    15 include $(srctree)/$(MACHINE)/Makefile.boot ==> arch/arm/mach-exynos/Makefile.boot
    1 zreladdr-y += 0x40008000 uImage的启动地址
    2 params_phys-y := 0x40000100 传参位置

    obj 当前Makefile路径
    78 $(obj)/uImage: $(obj)/zImage FORCE ==> 表示强制生成 uImage 生成需要zImage生成

    54 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE zImage生成需要arch/arm/boot/compressed/vmlinux

    51 $(obj)/compressed/vmlinux: $(obj)/Image FORCE
    52 $(Q)$(MAKE) $(build)=$(obj)/compressed $@

    make -C arch/arm/boot/compressed/ arch/arm/boot/compressed/vmlinux

    进入arch/arm/boot/compressed/Makefile

    185 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o
    186 $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3)
    187 $(bswapsdi2) FORCE

    vmlinux.lds 依赖于 vmlinux.lds.in 和 上层路径下的Makefile 和kconfig
    25 HEAD = head.o (由当前目录下的head.S生成)
    86 suffix_$(CONFIG_KERNEL_GZIP) = gzip
    piggy.gzip.o 指的就是gzip压缩 压缩代码

    195 $(obj)/piggy.$(suffix_y).o: $(obj)/piggy.$(suffix_y) FORCE
    192 $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE piggy.gzip.o 生成是依赖于上层路径下的Image

    addprefix 进行拼接路径
    OBJS 需要的目标库文件(很多)
    lib1funcs 功能相关库文件
    148 lib1funcs = $(obj)/lib1funcs.o
    154 ashldi3 = $(obj)/ashldi3.o 与工具链相关
    160 bswapsdi2 = $(obj)/bswapsdi2.o 与压缩格式相关代码

    回到arch/arm/boot/Makefile
    47 $(obj)/Image: vmlinux FORCE 表示的是顶层路径下的vmlinux

    回到顶层路径下的Makefile
    817 vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
    809 vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
    802 export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
    803 export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) 全部包含
    804 export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds


    530 init-y := init/
    531 drivers-y := drivers/ sound/ firmware/
    532 net-y := net/
    533 libs-y := lib/
    534 core-y := usr/

    head-y = head.o(arch/arm/kernel/head.S生成的文件) 启动的第一个文件
    KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds arch/arm/kernel/vmlinux.lds
    就能生成我们所需的uImage

    vmlinux.lds .lds链接脚本 生成vmlinux文件的工具
    vmlinux 真正的内核程序
    Image 经过第一次压缩
    zImage 经过第二次压缩
    uImage 使用了mkimage 添加头部,为了uboot的识别

    vmlinux 60M (没有添加其他驱动,只是默认配置,实际添加过后应为70M左右)
    Image 5M左右
    zImage 2768232
    uImage 2768296 uImage比zImage大64B 是由mkimage添加64B头部 此头部就是为了uboot进行识别来使用的头部(uboot的版本相关)

    uboot加载内核后 uImage 读走头部 ——> zImage 进行decopressed Image ——> vmlinux (真正执行在开发板中的程序)

    uImage的编译流程是启动流程的逆序

    linux内核的启动流程
    进入的是arch/arm/kernel/head.S

    解压后进入内核执行(vmlinux) 说明了一些当前所处状态 0xc0008000是虚拟地址的起始位置 uImage执行位置0x40008000
    __HEAD 开始位置
    thumb指令 使能thumb指令集
    CONFIG_的宏都在.config进行查找
    89 bl __hyp_stub_install 设置异常向量表
    将arm的工作模式设置成为svc模式
    获取处理器id(真实处理器) r9 = cpuid
    95 bl __lookup_processor_type 比较当前处理器id和预置的处理器id,确定是否支持当前处理器 (返回信息r5=procinfo r9=cpuid )
    进入arch/arm/kernel/head-common.S
    153 adr r3, __lookup_processor_type_data 将__lookup_processor_type_data物理地址赋值给r3
    174 __lookup_processor_type_data: 结构体
    175 .long .
    176 .long __proc_info_begin
    177 .long __proc_info_end
    154 ldmia r3, {r4 - r6} r4 = .(当前虚拟地址位置) r5 = __proc_info_begin(proc_info虚拟地址位置) r6 = __proc_info_end(虚拟地址位置)
    155 sub r3, r3, r4 @ get offset between virt&phys r3 = 虚拟地址与物理地址的差值
    156 add r5, r5, r3 @ convert virt addresses to r5 = proc_info_begin真实物理地址
    157 add r6, r6, r3 @ physical address space r6 = proc_info_end 真实物理地址值
    proc_info_begin指明的是arch/arm/include/asm/procinfo.h 下proc_info_list结构体的开始位置
    30 unsigned int cpu_val; cpu预设值
    31 unsigned int cpu_mask; cpu掩码
    158 1: ldmia r5, {r3, r4} r3 = cpu_val r4 = cpu_mask(配置的cpuid)
    159 and r4, r4, r9 r9(通过检测cp15协处理器得到真实cpu型号) 进行真实运行与配置的比较 r4 = 比较结果
    teq r3,r4 比较结果与对应值相比
    如果配置cpu的型号与当前运行的cpu型号相同,返回并此时r5 = proc_info_list结构体开始地址
    回到arch/arm/kernel/head.S
    r10 = r5
    109 adr r3, 2f r3 = 当前物理地址位置
    110 ldmia r3, {r4, r8} r4 = 当前虚拟地址 r8 = PAGE_OFFSET
    111 sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)
    112 add r8, r8, r4 @ PHYS_OFFSET

    148 2: .long . ( 当前预置虚拟地址)
    149 .long PAGE_OFFSET (虚拟地址页偏移)
    为了创建页表做准备

    117 /*
    118 * r1 = machine no, r2 = atags or dtb (传参方式,uboot阶段确定的),
    119 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
    120 */

    121 bl __vet_atags (arch/arm/kernel/head-common.S ) 检测当前设备传参方式是那种 当前是设备树传参
    检测创建页表的准备工作是否完成
    128 bl __create_page_tables (创建页表)
    从0xc0008000开始虚拟地址完成一部分地址映射,完成的4M地址映射,目的是为了后续开启MMU、cache、TLBS做准备
    arch/arm/mm/proc-v7.S
    Initialise TLB, Caches, and MMU state ready to switch the MMU on 完成了MMU、cache、tlb的初始化操作,为了开启mmu做准备
    137 ldr r13, =__mmap_switched 要进行地址转换,但是前提是mmu开启
    144 1: b __enable_mmu
    441 mcr p15, 0, r5, c3, c0, 0 @ load domain access register
    442 mcr p15, 0, r4, c2, c0, 0 @ load page table pointer 进行CP15协处理器设置,进行使能mmu
    444 b __turn_mmu_on mmu开启
    ldr r13, =__mmap_switched(arch/arm/kernel/head-common.S) 完成虚拟地址转换
    81 adr r3, __mmap_switched_data
    82
    83 ldmia r3!, {r4, r5, r6, r7}
    104 b start_kernel(完成了各种初始化任务)
    ||
    /
    init/main.c
    asmlinkage 表示进行编译器优化
    初始化死锁hash表,对分区进行锁定;防止堆栈溢出;
    使能中断;
    509 setup_arch(&command_line); (arch/arm/kernel/setup.c )
    包含了所有传入参数的赋值,赋值给了machine_desc结构体(arch/arm/include/asm/mach/arch.h )

    分配传入启动参数(bootargs参数);设置中断优先级;关闭中断原始优先级;初始化符号链接;
    非法闯入报警;
    581 console_init(); 串口显示,之前的打印内容将会保存到日志缓冲区中,初始化完成进行输出
    652 rest_init();
    382 kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
    ||
    /
    kernel_init
    840 kernel_init_freeable();
    926 if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
    927 ramdisk_execute_command = NULL;
    928 prepare_namespace();
    ||
    /
    init/do_mounts.c
    589 mount_root();
    509 if (ROOT_DEV(nfs机制是当做载体) == Root_NFS) {
    510 if (mount_nfs_root())
    459 err = do_mount_root(root_dev, "nfs",root_mountflags, root_data);
    362 int err = sys_mount(name, "/root", fs, flags, data);
    这样完成了nfs文件系统的挂载,而最后进入最终的文件系统,系统启动完成

    内核启动过程中
    汇编阶段:地址转换,完成物理地址转换为虚拟地址,开启MMU、cache、tlb
    c语言阶段:各种初始化,初始化完成后,开启线程,准备用户空间,挂载文件系统

    设备树简述
    定义:Device Tree是一种描述硬件的数据结构
    设备树文件书写格式
    /{
    property(根节点)
    node1{(子节点)
    property
    child_node{
    property
    };
    };

    node2{

    };

    };

    节点中的内容就是需要的设备信息

    dts 设备树源文件
    dtsi 设备树头文件 (由多款板子共用同一个头文件,与soc相关)
    dtb 设备树的可执行文件

    根节点属性(用来描述当前板级结构)
    model :表示具体某一个machine
    compatible:表示支持的一系列machine

    子节点属性(描述当前节点设备)
    node标注的值是确定的(驱动)
    compatible:用来绑定一个驱动和设备
    reg:可寻址设备用来表示编码地址信息

    其他节点属性:参考Documentation/devicetree/bindings

    设备树与machine_desc的关系
    在内核启动过程中设备树中的信息被转换为machine_desc结构体(setup_arch函数中完成了我们的赋值任务)

    作业:实验9、实验10


  • 相关阅读:
    python环境搭建以及jupyter notebook的安装和启动
    Python base(三)
    Python base(二)
    Python base(一)
    python之装饰器
    python 内置函数 (二)
    函数的简单写法
    python中set的用法
    python在终端运行时增加一些效果
    序列化写到类里
  • 原文地址:https://www.cnblogs.com/renchong/p/5756301.html
Copyright © 2020-2023  润新知