常用书目下载地址: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)

以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)

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...\n", 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秒的时间窗口内处理完成,数据就依然有效。但如果错过了某个嘀嗒,全球定位系统就可能会产生几英尺或甚至几英里的误差!

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

《嵌入式Linux基础教程学习笔记一》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. HDU 1525 Euclid's Game (博弈)

    Euclid's Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  2. 查看80端口被占用的方法(IIS、apmserv、system)

    端口如果被其他程序占用就不能正常启动,比如有时启动时会提示WEB启动失败,其实就是80 端口被占用了,而迅雷等下载软件恰恰就是占用了80端口,关掉就行了.但有时迅雷等都没有开 也启动不了,那就是别的东 ...

  3. MyEclipse中无法将SVN检出来的项目部署到tomcat中

    自己遇到的小问题  : 要以web项目方式从svn上倒下来才可以部署到tomcat下检出步骤: myEclipse -->File-->new-->other-->svn--& ...

  4. CreateWaitableTimer和SetWaitableTimer函数(定时器)

    用户感觉到软件的好用,就是可以定时地做一些工作,而不需要人参与进去.比如每天定时地升级病毒库,定时地下载电影,定时地更新游戏里的人物.要想 实现这些功能,就可以使用定时器的API函数CreateWai ...

  5. DataTemplate和ControlTemplate的关系

    DataTemplate和ControlTemplate的关系(转载自haiziguo) 一.ContentControl中的DataTemplate 在开始之前,我们先去看一下ContentCont ...

  6. Oracle Job相关

    Oracle JOB的建立,定时执行任务      begin            sys.dbms_job.submit(job => :job,                       ...

  7. android自定义相册 支持低端机不内存溢出

    1 之前在网上看的自定义相册很多时候在低端机都会内存溢出开始上代码把 首先我们要拿到图片的所有路径 cursor = context.getContentResolver().query( Media ...

  8. xampp 修改mysql 密码

    编辑 lampp/etc/extral/httpd-xampp.conf 文件注释掉 连上mysql,修改mysql下root 用户的登入密码为123456,执行 UPDATE user SET pa ...

  9. c++ 中文字符串处理方法

    转自:http://hi.baidu.com/hehehehello/item/dcc44a4a6afc690e6dc2f08b C++处理中文的问题困扰我很久了.之前一旦遇到中文基本就投诸java怀 ...

  10. 【转】深入浅出REST

    转自:http://www.infoq.com/cn/articles/rest-introduction 不知你是否意识到,围绕着什么才是实现异构的应用到应用通信的“正确”方式,一场争论正进行的如火 ...