zoukankan      html  css  js  c++  java
  • 《嵌入式Linux基础教程学习笔记一》

    常用书目下载地址:http://www.cnblogs.com/pengdonglin137/p/3688029.html

    第二章

    1、进程上下文和中断上下文(Page20)

    当应用程序执行系统调用,造成上下文的切换而进入内核时,内核会代表这个进程执行内核代码。你会经常听到,这种情况称为内核运行于进程上下文中。相反,处理IDE驱动器的中断处理程序(ISR)也是内核代码,但运行时并不代表任何特定的进程。这种情况通常被称为内核运行于中断上下文中。

    2、独立处理器、配套芯片组和集成处理器 (Page26)

          独立处理器是指那些专注于指令处理功能的处理器。与集成处理器相比,独立处理器需要额外的支持电路完成其基本操作。在大多数情况下,这意味着处理器周围需要配备一个芯片组或者一个定制的逻辑芯片,已实现一些增强功能,包括DRAM控制器、系统总线寻址配置以及外围设备(比如键盘控制器和串行端口)。独立处理器一般会提供最强的整体CPU性能。

    单独处理器都需要连接支撑逻辑芯片才能访问外设,这些外设包括系统主内存(DRAM)、ROM或者闪存、系统总线(比如PCI)或者其他外设,比如键盘控制器、串行端口和IDE接口,诸如此类。执行逻辑芯片的的功能一般由配套的芯片组来完成,而这个芯片组很可能是专门为某个系列的处理器设计的。

    虽然独立处理器的应用很广泛,包括一些高负载处理引擎,但是大多数的小型嵌入式系统都采用某种集成处理器或者片上系统(System On Chip,SOC)。

    参考阅读:

    http://pan.baidu.com/s/1eQGbs5c

    http://www.cnblogs.com/pengdonglin137/p/3690410.html

    3、查询本机的内核的发布信息

    cat /proc/version

    4、顶层源码目录

    在本书中,会常常提到顶层源码目录。这时,我们指的是内核源码树的最高一层目录。顶层源码目录包含以下列出的子目录:

                arch/         block/         crypto/        Documentation/ 
                drivers/     firmware/    fs/               include/   
                init/          ipc/             kernel/         lib/ 
                mm/         net/            samples/      scripts/   
                security/    sound/       usr/              virt/

    5、编译内核是显示详细编译过程

    如: make  ARCH=arm CROSS_COMPILE=arm-linux- V=1 uImage

       1: make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
       2: make V=2   [targets] 2 => give reason for rebuild of target
       3: make O=dir [targets] Locate all output files in "dir", including .config
       4: make C=1   [targets] Check all c source with $CHECK (sparse by default)
       5: make C=2   [targets] Force check of all c source with $CHECK

    6、清理

    有几个make命令会删除配置文件而不会给出任何警告。最常见的就是make distclean(此外还有make mrproper)。这个make目标的设计初衷是上内核代码树回到原始的、未配置的状态。这包括删除源码树中所有的配置数据,当然也会删除原先的.config文件。

       1: Cleaning targets:
       2:   clean          - Remove most generated files but keep the config and
       3:                     enough build support to build external modules
       4:   mrproper      - Remove all generated files + config + various backup files
       5:   distclean      - mrproper + remove editor backup and patch files

    7、bzImage和zImage  (Page61)

    很多架构和机器类型都需要一个二进制镜像目标,而这个目标与具体使用的架构和引导加载程序有关。比较常见的这类目标是zImage。对于很多架构来说,这就是默认的二进制镜像目标,可以被加载到目标嵌入式系统中并运行。新手常犯的一个错误就是将bzImage指定为make的目标。然而,bzImage目标是针对x86/PC架构的。有一个常见的错误观点,认为bzImage是指经过压缩工具bzip2压缩过的镜像,其实不然,bzImage是指大(big)的zImage。

    8、make menuconfig

    在顶层目录执行make menuconfig ,然后再顶层Makefile中的:

    459 %config: scripts_basic outputmakefile FORCE
    460         $(Q)mkdir -p include/linux include/config
    461         $(Q)$(MAKE) $(build)=scripts/kconfig $@

    %config可以匹配*config,然后进入script/kconfig中执行 make  menuconfig,

    7 ifdef KBUILD_KCONFIG
    8 Kconfig := $(KBUILD_KCONFIG)
    9 else
    0 Kconfig := arch/$(SRCARCH)/Kconfig
    1 endif
    2 
    3 xconfig: $(obj)/qconf
    4         $< $(Kconfig)
    5 
    6 gconfig: $(obj)/gconf
    7         $< $(Kconfig)
    8 
    9 menuconfig: $(obj)/mconf                                                    
    0         $< $(Kconfig)
    1 
    2 config: $(obj)/conf
    3         $< $(Kconfig)
    4 
    5 oldconfig: $(obj)/conf
    6         $< -o $(Kconfig)

    其中Kconfig是arch/arm/Kconfig,对于menuconfig,配置工具是mconf,他可以解析Kconfig文件。

    9、嵌入式Linux发行版所包含的的组件   (Page73)

    Linux内核

    引导加载程序,你需要将它移植到特定的硬件平台上,并做相应的配置;

    适合于你所选架构的交叉编译器和相关的工具链

    文件系统,其中包含很多软件包——主要是二进制可执行文件和程序库,而且他们是针对本地硬件架构和处理器而编译的;

    设备驱动程序,内核通过它们访问硬件板卡上的定制硬件;

    开发环境,包括主机上的工具和软件;

    Linux内核源码树,并且适合于特定的处理器和硬件板卡;

    10、单体内核

    Linux采用单体(monolithic)内核结构。也就是说,这个内核是由代码编译并静态链接生成的,是一个单一的可执行文件。然而,也可以编译一组源码文件,并通过增量链接的方式生成一个对象模块,他可以动态加载到运行的内核中。

    内核的构建过程,不管采用哪种架构,构建时都会生成一些通用文件,其中之一就是名为vmlinux的ELF二进制文件(处于顶层内核源码目录中)。这个二进制文件就是单体内核(monolithic kernel)本身,我们也称它为内核主体。

    下面是tq2440在生成内核源码顶层目录下的vmlinux时的链接命令:

    arm-linux-ld -EL  -p --no-undefined -X --build-id -o vmlinux  
                                                                  
    -T arch/arm/kernel/vmlinux.lds                                
                                                                  
    arch/arm/kernel/head.o                                        
    arch/arm/kernel/init_task.o                                   
                                                                  
    init/built-in.o                                               
    --start-group                                                 
    usr/built-in.o                                                
                                                                  
    arch/arm/kernel/built-in.o                                    
    arch/arm/mm/built-in.o                                        
    arch/arm/common/built-in.o                                    
    arch/arm/mach-s3c2410/built-in.o                              
    arch/arm/mach-s3c2400/built-in.o                              
    arch/arm/mach-s3c2412/built-in.o                              
    arch/arm/mach-s3c2440/built-in.o                              
    arch/arm/mach-s3c2442/built-in.o                              
    arch/arm/mach-s3c2443/built-in.o                              
    arch/arm/plat-s3c24xx/built-in.o                              
    arch/arm/plat-s3c/built-in.o                                  
    arch/arm/nwfpe/built-in.o                                     
                                                                  
    kernel/built-in.o                                             
    mm/built-in.o                                                 
    fs/built-in.o                                                 
    ipc/built-in.o                                                
    security/built-in.o                                           
    crypto/built-in.o                                             
    block/built-in.o                                              
    arch/arm/lib/lib.a                                            
    lib/lib.a                                                     
    arch/arm/lib/built-in.o                                       
    lib/built-in.o                                                
    drivers/built-in.o                                            
    sound/built-in.o                                              
    firmware/built-in.o                                           
    net/built-in.o                                                
                                                                  
    --end-group .tmp_kallsyms2.o
     

    11、内核是如何合成的? (具体需要参见第五章的第一节P75)

    image

    以arm为例,其中vmlinusx 在内核源码顶层目录,Image在arch/arm/boot/下,piggy.gz在arch/arm/boot/compressed/下,bootable kernel image在arch/arm/boot/下。

    这里主要说明如下俩个概念的不同:启动加载程序(Bootstrap Loader)和引导加载程序(Bootloader)

    引导加载程序简单理解为uboot或者Bootloader或者第1阶段的加载程序,可以将启动加载程序看做是第2阶段的加载程序(简单理解为:zImage头部的几个文件,负责初始化设置一些硬件以及解压内核镜像的部分)。

    不要将启动加载程序和引导加载程序混淆,很多架构都使用启动加载程序(第2阶段加载程序)将Linux内核镜像加载到内存中。有些启动加载程序会对内核镜像进行校验和检查,而大多数启动加载程序会解压并重新部署内核镜像。引导加载程序和启动加载程序之间的区别也很简单:但硬件单板加电时,引导加载程序获得其控制权,根本不依赖内核。相反,启动加载程序的主要作用是作为裸机引导加载程序和Linux内核之间的粘合剂。启动加载程序负责提供合适的上下文让内核运行于其中,并且执行必要的步骤以解压和重新部署内核二进制镜像。这类似于PC架构中的主加载程序和次加载程序的概念。

    启动加载程序和内核镜像拼接在一起,用于加载。

    (具体参见:Page79)

    image

    12、查看内核初始化细节  (page96)

    initcall_debug是一个很有趣的内核命令行参数,它允许你观察启动过程中的函数调用。只需在启动内核是设置一下initcall_debug,就可以看到系统输出相关的诊断信息:

    下面initcall最后的return x after XX usecs 表示函数的返回值以及函数调用的持续时间。

    calling  spi_init+0x0/0x84 @ 1
    initcall spi_init+0x0/0x84 returned 0 after 2936 usecs
    calling  i2c_init+0x0/0x60 @ 1
    initcall i2c_init+0x0/0x60 returned 0 after 4214 usecs
    calling  customize_machine+0x0/0x24 @ 1
    S3C Power Management, Copyright 2004 Simtec Electronics
    initcall customize_machine+0x0/0x24 returned 0 after 22922 usecs

    这是个查看内核初始化细节的好办法,特别是可以了解内核调用各个子系统和模块的顺序。更有趣的是函数调用的持续时间。如果你关心系统启动时间,通过这种方法可以确定启动时间是在哪些地方被消耗的。

    13、根文件系统

    根文件系统指的是挂在于文件系统层次结构根部的文件系统,简单表示为/。

    简单来说,根文件系统是内核挂载的第一个文件系统,挂载位置是文件系统层次结构的顶端。

    Linux系统对于根文件系统有一些特殊需求。Linux要求根文件系统中包含应用程序和工具软件,通过它们来引导系统、初始化系统服务(比如网络和系统控制台)、加载设备驱动程序和挂在额外的文件系统。

    14、根文件系统中的glibc和Linux动态加载器

    在嵌入式系统的根文件系统中一般都会有这两个动态库:glibc(如libc-XXX.so)和Linux动态加载器(如ld-XXX.so)。其中glibc包含标准C程序库的函数,比如printf()和很多其他大多数的应用程序都依赖的常用函数。

    Linux动态加载器负责将二进制程序加载到内存中,并且,如果应用程序引用了共享库中的函数,它还需要执行动态链接。

    15、定制用户空间初始化程序

    在init/main.c中:

    if (execute_command) {
        run_init_process(execute_command);
        printk(KERN_WARNING "Failed to execute %s.  Attempting "
                    "defaults...
    ", execute_command);
    }
    run_init_process("/sbin/init");
    run_init_process("/etc/init");
    run_init_process("/bin/init");
    run_init_process("/bin/sh");
     
    panic("No init found.  Try passing init= option to kernel.");

    在上面的语句中,如果execute_command非空,它会指向一个运行在用户空间的字符串,而这个字符串中包含了一个定制的、由用户提供的命令。开发人员在内核命令行中指定这个命令,并且他会由我们前面所研究的__setup宏进行设置。

    在init/main.c中:

    static int __init init_setup(char *str)
    {
        unsigned int i;
     
        execute_command = str;
        /*
         * In case LILO is going to boot us with default command line,
         * it prepends "auto" before the whole cmdline which makes
         * the shell think it should execute a script with such name.
         * So we ignore all arguments entered _before_ init=... [MJ]
         */
        for (i = 1; i < MAX_INIT_ARGS; i++)
            argv_init[i] = NULL;
        return 1;
    }
    __setup("init=", init_setup);

    在include/linux/init.h中:

    #define __setup_param(str, unique_id, fn, early)            
        static char __setup_str_##unique_id[] __initdata __aligned(1) = str; 
        static struct obs_kernel_param __setup_##unique_id    
            __used __section(.init.setup)            
            __attribute__((aligned((sizeof(long)))))    
            = { __setup_str_##unique_id, fn, early }
     
    #define __setup(str, fn)                    
        __setup_param(str, fn, fn, 0)

    下面是一个内核命令行的例子:

    initcall_debug init=/sbin/myinit console=ttyS1,115200 root=/dev/hda1

    含义:

    内核显示所有的初始化函数调用,配置初始的控制台设备/dev/ttyS1,其数据速率为115Kbit/s,并执行一个定制的、名为myinit的用户空间初始化进程,这个程序位于根文件系统的/sbin目录中。它还指导内核从设备/dev/hda1挂载器根文件系统,这个设备是第一个IDE硬盘。

    注意一下,一般来说,内核命令行中各个参数的先后次序无关紧要。

    16、应用程序依赖关系

    大多数应用程序有两类依赖关系:

    1、动态链接的应用程序对程序库的依赖,这种应用程序中包含未解决的引用,这需要由程序库提供;

    2、应用程序可能需要的外部配置文件或者数据文件

    对于前者,可以使用工具来确定,这里介绍两种方法(XXX代表可执行程序):

    1、ldd xxx

    2、objdump –x xxx | grep NEEDED

    对于后者,至少要对相关的应用程序有个基本了解。

    17、rmmod 和 modprobe –r

     如:modprobe –r ext3 可以用于删除模块,包括某个模块所依赖的模块,而rmmod不会删除一个模块所依赖的模块。

    18、 /proc 、sysfs以及tmpfs

    他们俩个都是伪文件系统(Pseudo File Systems)。

    /proc 文件系统的名称源于他的最初设计目的:它是一个接口,内核通过它可以获取一个Linux系统上所有进程的信息。随着时间的推移,它也不断发展壮大,可以提供更多方面的信息,而不仅限于进程。很多用户空间的应用程序都依靠/proc文件系统中的内容来完成它的工作。例如mount命令,如果在执行时不带任何参数,会列出系统中当前所有已挂载文件系统的信息,而它是从/proc/mounts文件中获取这些信息的。如果不存在/proc文件系统,mount命令直接返回。除了mount之外,其他一些与/proc文件系统交互的实用程序还有free、pkill、pmap以及uptime。请参考procfs软件包获取更多信息。

    挂载/proc文件系统:  mount –t proc /proc /proc 或者 mount –t proc none /proc

    sysfs是对具体的内核对象(比如物理设备)进行建模,并且提供一种将设备和设备驱动程序关联起来的方法。从sysfs中可以获取很多系统信息,很多实用工具都使用了这些信息,比如电源管理和热插拔能力,还有mtd-utils中的很多与Flash操作相关的工具。

    tmpfs中的所有内容都是存储在内核的虚拟内存中的,断电或者重启后,这些内容都丢失了。tmpfs文件系统对于快速临时文件存储很有用。对于那些会使用很多小的临时文件的应用程序来说,这可以提高它们的性能。

    挂载tmpfs文件系统:  mount –t tmpfs /tmpfs /tmp 或者 mount –t tmpfs none /tmp

    嵌入式系统中自动挂载这三种文件系统一般在/etc/fstab中设置:

       1:  # cat /etc/fstab 
       2:  proc            /proc           proc    defaults        0       0
       3:  sysfs           /sys            sysfs   defaults        0       0
       4:  tmpfs           /dev            tmpfs   defaults        0       0
       5:  tmpfs           /tmp            tmpfs   defaults,size=120M      0       0
       6:  tmpfs           /var/run            tmpfs       defaults        0       0

    19、MTD概述

          内存技术设备(Memory Technology Device,MTD)子系统的目的是让内核支持种类繁多的类似内存的设备,比如闪存芯片。市面上有很多不同种类的闪存芯片,对它们进行编程的方法也多种多样,主要原因是它们要支持很多特殊和高效的模式。MTD子系统采用了层次化架构,将底层设备的复杂性和(使用这些内存和闪存设备的)高层的数据组织及存储格式分隔开。

          简单来说,MTD是一个设备驱动程序层,它提供了一套访问原始闪存设备的通用API接口。MTD支持很多种闪存设备。然而,MTD不是块设备。MTD与设备打交道时是以擦除块(erase block)为单位的,其大小不一,而块设备是以固定大小的块(称为扇区)位操作单位的。块设备有两种主要操作——读取扇区和写入扇区,而MTD有3种:读、写和擦除。MTD设备的写寿命是有限的,所以MTD会包含内部逻辑将写操作分布开来已延长设备的寿命,这被称为损耗均衡(wear leveling)。

    与通常的想法相反,SD/MMC卡、CompactFlash卡、USB闪存盘以及其他一些类似的设备都不属于MTD设备。这些设备的内部都包含了闪存转换层,用于完成类似MTD的功能,比如块擦除和损耗均衡。因此,对于系统来说,它们看上去就像是传统的块设备,不需要经过MTD的特殊处理。

    Linux中的大多数设备属于字符设备或者块设备中一种。而MTD既不是字符设备,也不是块设备。虽然一些转换机制可以使MTD看起来像字符设备或块设备,但是在Linux驱动架构中,MTD有其独特之处。这是因为MTD驱动程序必须完成一些闪存特有的操作,比如块擦除操作和损耗均衡,而传统的块设备驱动程序是没有类似操作的。

    20、软实时和硬实时

    软实时

    大多数人都同意软实时意味着操作有时间限制。如果超过了时间限制后操作还没有完成的话,体验的质量就会下降,但不会带来致命后果。桌面工作站就是一个需要软实时的绝好的例子。编辑文档时,你期望按键之后立刻在屏幕上看到结果。在播放mp3文件时,你期望听到没有任何杂音、爆音或者中断的高品质音乐。

    一般而言,普通人无法分辨出小于几十毫秒的延时。当然音乐家能够听出比这更短的延时,并且告诉你它们影响了音乐的质量。如果这些所谓的软实时事件错过了时限,结果可能不尽如人意,并导致体验的质量有所下降,但这并不是灾难性的。

    硬实时

    硬实时的特点是错过时限会造成严重结果。在一个硬实时系统中,如果错过了时限,后果往往是灾难性的。当然,“灾难”是相对而言的。但如果你的嵌入式设备正在控制喷气式飞机引擎的燃料流,而它没能及时的响应飞行员输入的命令或者操作特性的变化,致命后果就不可避免了。

    注意,时限的持续时间并不是硬实时的特征。原子钟中处理每个嘀嗒的服务程序就是这样的例子。只要在下一个嘀嗒到来之前的持续1秒的时间窗口内处理完成,数据就依然有效。但如果错过了某个嘀嗒,全球定位系统就可能会产生几英尺或甚至几英里的误差!

    考虑到这一点,我们借鉴了一组常用的软实时和硬实时的定义。对于软实时系统,如果错过的了时限,系统的计算值或者结果会不太理想。然而,对于硬实时系统,如果错过了某个时限,系统就是失败的,而且可能会造成灾难性的后果。

     

  • 相关阅读:
    python练习--1、简易登录接口
    python--1、入门
    mysql数据库安装
    第八章总结
    第七章总结
    第三周总结
    第二周总结
    if、switch语句
    2章总结
    1月14日总结
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/3687658.html
Copyright © 2011-2022 走看看