正文:

  1. 除了平常的CPU,MCU,MPU可以运行LINUX,DSP同样也可以,DSP可分为两类:定点和浮点DSP,DSP包含独立的硬件 乘法器,DSP和乘法指令一般在单周期内完成,且优化了卷积,数字滤波,FFT,相关矩阵运算等算法中的大量重复乘法.
  2. 网络处理器器件内部通常由若干微码处理器和若干硬件协处理器组成,多个微码处理器在网络处理器内部并行处理,通过 预先编制的微码来控制处理流程.
  3. FLASH的编程原理都是只能将1写为0.flash存在一个负载均衡问题,不能老是在同一块位置进行擦除和写的动作,这样 容易导致坏块.
  4. USB 3.0线缆设计了8条内部线路,除VBUS,电源地之外,其余3对均为数据传输线路.在USB架构中,集线器负责检测设备的连接和断开, 利用其中断IN端点来向主机报告.一旦获悉有新设备连接上来,主机就会发送一系列请求给设备所挂载的集线器,再由集线器建立起一条连接 主机和设备之间的通信通道.
  5. 以太网隔离变压器是以太网收发芯片与连接器之间的磁性组件,在两者之间起着信号传输,阻抗匹配,波形修复,信号杂波抑制和高电压隔离 作用.
  6. PCI配置空间保存着该卡工作时所需的所有信息,如厂家,卡功能,资源要求,处理能力,功能模块数量,主控卡能力等.
  7. Buddy算法在内核底层中用于管理每个页的占用情况,内核空间的slab以及用户空间的C库的二次管理.
  8. 在linux在网络接口可分为网络协议和网络驱动程序,网络协议部分负责实现每一种可能的网络传输协议,网络设备驱动程序负责与硬件设备 通信.
  9. LINUX支持进程间的多种通信机制,包含信号量,共享内存,消息队列,管道,socket,信号等.
  10. ARM处理器分为7种工作模式:用户模式(usr,大多应用程序运行在此模式下,一些被保护的资源不能访问),快速中断模式(fiq,用于高速 数据传输或通道处理),外部中断模式(irq,用于通用的中断处理),管理模式(svc,操作系统使用的保护模式),数据访问中止模式(abt,当数据或指令 预取中止时进入此模式,用于虚拟存储及存储保护),系统模式(sys,运行具有特权的操作系统任务),未定义指令中止模式(und,可用于支持硬件协 处理器的软件访真).
  11. linux只能通过系统调用(其实是软中断)或硬件中断来完成从用户空间到内核空间的转移.
  12. 内核模块可以导出符号(symbol),若导出,其他模块则可以使用本模块中的变量或函数.
  13. VFS与文件系统以及设备文件之间的接口是file_operations结构体成员函数.
  14. 块设备有两种访问方法,一种是不通过文件系统直接访问裸设备,在LINUX内核实现了统一的def_blk_fops这一file_operations;另一种是通过文件系统来访问块设备,file_operations的实现则位于文件系统内,文件系统会把针对文件的读写转换为针对块设备原始扇区的读写.
  15. file结构体代表一个打开的文件,系统中每个打开的文件在内核空间都有一个关联的 struct file,它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数.在文件的所有实例都关闭后,内核释放file结构体.
  16. VFS inode包含文件访问权限,属主,组,大小,生成时间,访问时间,最后修改时间等信息.它是LINUX管理文件系统的最基本单位,也是文件系统连接任何子目录,文件的桥梁.
  17. 主设备号是与驱动相对应的.
  18. udev完全在用户态工作,利用设备加入或移除时内核所发送的热插拔事件来工作(在热插拔时,设备的详细信息会由内核通过netlink发送出来).在嵌入式系统中,也可以用udev的轻量级版本mdev,mdev集成于busybox中.
  19. mmap()函数将设备内存映射到进程的虚拟进程空间中,如果设备驱动未实现此函数,用户进行mmap()系统调用时会获得-ENODEV返回值.
  20. 内核空间在访问用户空间的缓冲区之前,要先检查其合法性,通过access_ok()来进行判断.内核的许多安全漏洞都是因为没检查合法性造成的,非法侵入者可以假造一片内核空间的缓冲区传入系统调用的接口,让内核对这个指针指向的内核空间填充数据.
  21. 在linux2.6.35之后,内核直接取消了中断的嵌套.
  22. 现代的高性能编译器在目标码优化上都具备对指令进行乱序优化的能力,以减少逻辑上不必要的访存,以及尽量提高Cache命中率和CPU的load/store单元的工作效率.
  23. 乱序执行:高级的CPU可以根据自己缓存的组织特性,将访存指令重新排序执行.连续地址的访问可能会先执行,因为这样缓存命中率高,有的还允许访存的非阻塞.
  24. ARM处理器的屏障指令包括:DMB(数据内存屏障),DSB(数据同步屏障),ISB(指令同步屏障).
  25. 当程序在访问外设的寄存器时,这些寄存器的访问顺序在CPU的逻辑上构不成依赖关系,但是从外设的逻辑角度来讲,可能要固定的寄存器读写顺序,这时也得使用CPU的内存屏障指令.
  26. RCU(Read-copy-update):RCU的写执行单元在访问它的共享资源前首先复制一个副本,然后对副本进行修改,最后使用一个回调机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据.,这个时机就是所有引用该数据的CPU都退出共享数据读操作时.等待适当时机的这一时期称为宽限期.
  27. 阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作,被挂起的进程进入睡眠状态,被从调度器的运行队列移走,直到等待的条件被满足.
  28. 异步通知:一旦设备就绪,则主动通知应用程序,这样应用程序就不要查询设备状态.在信号中,除了SIGSTOP,SIGKILL两个信号外,进程能够忽略或捕获其他的全部信号.一个信号被捕获的意思是当一个信号到达时有相应的代码处理它,如果一个信号没有被这个进程捕获,内核将采用默认行为处理. void (signal (int signum,void ( handler))(int)) (int);
  29. linux的AIO(异步IO)有多种实现,其中一种实现是在用户空间的glibc库中实现的,它本质上是借用了多线程模型,用开启新的线程以同步的方法来做IO,新的AIO辅助线程与发起AIO的线程以pthread_cond_signal()的形式进行线程间的同步.对于网络设备而言,在socket层面上,也可以使用AIO,让CPU和网卡的收发动作充分交叠以改善吞吐性能.AIO一般由内核空间的通用代码处理.
  30. 内核对时钟的处理采用中断方式,而内核软件定时器最终依赖于时钟中断.
  31. 非向量中断的多个中断共享一个入口地址,进入该地址后,再通过软件判断中断标志来识别具体是哪个中断.而向量中断由硬件提供中断服务程序入口地址.
  32. 在软中断和tasklet中不能睡眠.
  33. 内核在时钟中断发生后检测各定时器是否到期,到期后的定时器处理函数将作为软中断在下半部执行.实质上,时钟中断处理程序会唤起TIMER_SOFTIRQ软中断,运行当前处理器上到期的所有定时器.
  34. TTW(Translation table walk):转换表漫游,当TLB中没有缓冲对应的地址转换关系时,需要通过对内存中转换表的访问来获得虚拟地址和物理地址的对应关系,TTW成功后将结果写入TLB中.
  35. ARM内TLB条目中的控制信息用于控制对对应地址的访问权限以及Cache的操作.(C(高速缓存)和B(缓冲)位被用来控制对应地址的高速缓存和写缓冲,并决定是否进行高速缓存.访问权限和域位用来控制读写访问是否被允许)
  36. 用户进程各自有不同的页表,而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的.内核空间的虚拟地址到物理地址映射是被所有进程共享的,内核的虚拟空间独立于其他进程.
  37. 大于896MB的物理内存时,超过896MB的内存称为高端内存,内核在存取高端内存时必须将它们映射到高端页面映射区.
  38. ARM系统的LINUX把内核模块安置在3GB附近的16MB范围内,主要是为了实现内核模块和内核本身的代码之间的短跳转.
  39. DMA,常规,高端内存这3个区域都采用buddy算法进行管理,把空闲的页面以2的n次方为单位进行管理,因此linux最底层的内存申请都是以2的n次方为单位的.
  40. C库的malloc()函数一般通过brk(),mmap()两个系统调用从内核申请内存.malloc算法实际上具备一个二次管理能力,所以并不是每次申请和释放内存都一定伴随着对内核的系统调用.此外,linux内核总是采用按需调页,因此当malloc()返回时,虽然是成功返回,但内核并没有真正给这个进程内存,这时如果去读申请的内存,内容全部是0,这个页面的映射是只读的.只有当写到某个页面时,内核才在页错误后,真正把这人页面给这个进程.
  41. kmalloc(),和 __get_free_pages() 申请的内存位于DMA和常规区域的映射区,而且在物理上也是连续的.在使用GFP_KERNEL标志申请内存时,若暂时不能满足,则进程会睡眠等待页,会引起阻塞,因此不能在中断上下文或持有自旋锁的时候使用它.
  42. 内存池技术用于分配大量小对象的后备缓存技术.
  43. ARM的写缓冲器是一个非常小的FIFO存储器,位于处理器与主存之间,其目的在于将处理器和Cache从较慢的主存写操作中解脱出来.写缓冲区与Cache在存储层次上处于同一层次,但是它只作用于写主存.
  44. 在驱动程序中实现VMA的fault()函数通常可以为设备提供更加灵活的内存映射途径.当访问的页不在内存里,即发生缺页异常时,fault()会被内核自动调用,而fault()的具体行为可以自定义.因为当发生缺页异常时,系统会找到缺页的虚拟地址所在的VMA,分配中间页目录表和页表(如果必要),如果页表项对应的物理页面不存在,则调用这个VMA的fault()方法,它返回物理页面的描述符,再将物理页面的地址填充到页表中.
  45. Cache不一致问题:当DMA的目的地址与Cache所缓存的内存地址访问有重叠,经过DMA操作,与Cache缓存对应的内存中的数据已经被修改,而CPU本身并不知道,它仍然认为Cache中的数据就是内存中的数据;除了前面这一情况下,它还存在于Cache使能和关闭的时刻.
  46. 内存中用于与外设交互数据的一块区域称为DMA缓冲区,在设备不支持SG(scatter/gather)操作的情况下,DMA缓冲区在物理上必须是连续的.
  47. linux总线,设备和驱动模型可以把设备端的信息从驱动里剥离出来.驱动只管驱动,设备只管设备,总线则负责匹配设备和驱动.在嵌入式系统里面,在SOC系统中集成的独立外设控制器,挂接在SOC内存空间的外设等却不依附于此类总线.基于此背景,Linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver.
  48. miscdevice框架结构用于在linux中不能确知其属于什么类型,它本质上也是字符设备,只是在miscdevice核心层的misc_init()函数中,通过register_chrdev(MISC_MAJOR,”misc”,&misc_fops)注册了字符设备,而具体miscdevice实例调用misc_register()的时候又自动完成了device_create(),获取动态次设备号的动作.
  49. 驱动核心层3大职责:对上提供接口;中间层实现通用逻辑;对下定义框架.
  50. IO调度层的基本目的是将请求按照它们对应在块设备上的扇区进行排列,以减少磁头的移动,提高效率.它可以将连续的bio合并成一个请求,请求是bio经由IO调度进行调整后的结果.linux内核包含4个IO调度器:Noop ,Anticipatory(后来从内核中去掉了), Deadline ,CFQ I/O调度器.

正文:


  1. exynos4412的mmc块设备的地址空间独立于CPU的地址总线。
  2. emmc数据总线宽度为一般为1(默认),4,8微。
  3. emmc I/F clock或boot频率为52Mhz以下。
  4. emmc支持背后自我操作,即当不在给CPU服务时,可以利用空闲时间自我操控自身。
  5. emmc由两个boot分区(每个512kB )和RPMB分区(128KB)及用户数据区组成。用户数据区可以被分成4个general purpose area partition和user data area partition.
  6. 我们在编写嵌入式系统时,时常是直接与硬件打交道,因此编写完代码之后在写连接脚本时对CPU的地址空间中的存储器地址必须清楚,不能弄错,特别是指定加载地址和运行地址(也可以叫做连接地址,即当程序运行时应该处于的硬件地址(CPU未打开MMU时的地址总线空间中的地址))所谓加载地址其实是原始代码或数据最开始所处的地址。一般由于嵌入式系统中的flash小,因此常常将代码和数据连续存到,当把代码和数据整个放入内存之后再在内存中进行重定位(从ram的一个空间区域copy到另一个区域),并不是直接从rom区一字节一一的放入指定的运行地址(stm32内置的flash除外,因为stm32中的内置的那512k的flash可以随机读取以字节,字,双字为单位的内容,只是写擦出时以块(页)为单位)。对于像2410,2440,44b0,6410,210等这些三星处理器,它把flash直接映射在cpu地址总线上的地址空间,而4412则是通过mmc控制器把emmc等mmc存储器地址独立于CPU地址总线的地址空间外。

一.前言:

由于最近在写点驱动程序,得重新用到gcc中的一些编译选项,以及给链接脚本指定相关的参数信息,过了许久没用它们,发现每用一个功能都得到网上查看下具体的参数选项,因此干脆把一些常用的记录下来,方便日后查阅.


二.正文:

  1. gcc —c hello.c 只会生成.o的obj文件,它只激活预处理,编译,汇编。 而—C是使在预处理时不删除注释信息,一般和—E一块使用,方便分析程序。
  2. objdump —s hello.o可以查看程序的所有内存区(.text,.rodata等)的内容。nm工具可以用来查看符号表。
  3. gcc —S hello.c只会激活预处理,编译,生成.S的汇编代码。
  4. gcc —E hello.c > hello.txt ,此选项只激活预处理,它不生成文件,你得重定向到一个输出文件里。
  5. gcc —pipe —o hello.o hello.c ,此选项只是用管道来替代编译中产生的临时文件。
  6. gcc hello.c —include stdio.h,其实就相当于#include
  7. —Idir是你在用#include “file.h”时,gcc会先在当前目前查找你所制定的头文件,如果没有找到,它会回到缺省的头文件目录找,如果使用了—I制定了目录,它会先在你所制定的目录中查找,然后再按照常规的顺序去查找。对于#include ,gcc也是先到你用—I所指定的目录去找,然后才会到系统默认目录找。
  8. —I—是用来取消上一个选项的功能。
  9. —idirafter dir是当在—I所指定的目录中找不到时才到此目录里找。
  10. —nostdinc使编译器不在系统缺省的头文件目录中找头文件。
  11. —llibrary指定编译时用的库,如gcc —lcurses hello.c.
  12. —Ldir用来制定编译时搜索库的路径。dir就是库所在的目录。
  13. —O0到—O3是编译器的四个优化级别,—O0表示没有优化。
  14. —g是让编译器在编译时产生调试信息。
  15. —static此选项将禁止使用动态库,所以编译出来的东西都比较大。
  16. —share此选项将尽量使用动态库。
  17. —traditional试图让编译器支持传统的C语言特性。
  18. —w让编译器不产生任何警告信息。
  19. —Wall生成所有警告信息。
  20. ar的常用用法:ar —t libname.a 显示所有对象。ar —rv libname.a obj1.o obj2.o把obj1,2打包成库文件。
  21. ar的其他选项:d 从库中删除模块;m 在一个库中移动成员;p 显示库中指定的成员到标准输出;q 快速追加新模块到库的结尾处;r 在库中插入或替换模块。
  22. gcc在ARM中所提供的常用选项:—mcpu, —mlittle—endian,—mbig—endian,—march,—mfpu,—mthumb.

链接器:
23. 链接器ld把一个或多个输入文件合成一个输出文件。目标文件中的每个section至少要包含两个信息:名字和大小。大部分section还包含与它相关的一块数据,称为section contents.一个section可以被标记为”loadable(可加载的)”或”allocatable(可分配的)”。
24. loadable section:在输出文件运行时,相应的section内容被载入到进程地址空间。
25. allocatable section:内容为空,在输出文件运行时,在进程地址空间中空出大小同section指定大小的空间,一般这块内存还得置0。 26. 对于设定了MEMOTY时,> 是设定对应段的运行地址。

最后给出gcc官方文档,以便查看其它的一些特性参数: gcc online document Link


*writer:victor *
** date:2016-05-01 13:10**

正文:

  1. sysfs表示系统设备树的一个文件系统。
  2. 块设备是以块为单位寻址的,块大小随设备不同而不同,它通常支持重定位操作,即对数据的随机访问(块为单位)。
  3. 应用程序通过直接访问设备节点与字符设备交互。
  4. 网络设备打破了unix的所有东西都是文件的设计原则,它得通过套接字API来访问。
  5. Linux是单块内核的操作系统,整个系统内核都运行于一个单独的保护域中。内核是模块化组成的,允许内核运行时动态插入和删除代码。
  6. 模块被载入后,会被动态地链接到内核,与用户空间中的动态链接库类似,只有当被显式导出后的外部函数才可以被动态库调用。导出内核函数可以用:export_symbol()和export_symbol_gpl().
  7. 导出的内核函数可以被模块调用。
  8. 具有相同的ktype的kobject可以被分组到不同的kset.
  9. sysfs文件系统是一个处于内存中的虚拟文件系统,为我们提供了kobject对象层次结构的试图,帮助用户能以一个简单的文件系统的方式来观察系统中各种设备的拓扑结构。
  10. 内核事件层实现了内核到用户空间的消息通知系统,它建立在kobject基础上,借助kobject和sysfs来实现。内核事件层把事件模拟为信号,从明确的kobject对象发出,所以每个事件源都是一个systs路径。内核事件由内核空间传递到用户空间需要经过netlink(netlink用于传递网络信息的多点传送套接字)。

正文:

  1. 内核提供了用户进程与内核进行交互的一组接口,这些接口让应用程序受限地访问硬件设备,提供了创建新进程并与已有进程进行通信的机制,也提供了申请操作系统其他资源的能力。
  2. Linux的系统调用作为C库的一部分,C库实现了系统的主要API,包括标准C库函数和系统调用接口。
  3. 系统调用在出现错误的时候C库会把错误码写入errno全局变量。通过perror()库函数,可以把该变量翻译成用户可以理解的错误字符串。
  4. 函数声明中的asmlinkage限定词,是一个编译指令,通知编译器仅从栈中提取该函数参数。
  5. 在Linux中,每个系统调用被赋予一个系统调用号。当用户空间的进程执行一个系统调用的时候,这个系统调用号就用来指明到底是要执行哪个系统调用。进程不会提及体统调用的名称!
  6. 内核记录了系统调用表中所有已注册过的系统调用的列表,存储在sys_call_table中(arch//kernel/syscall.c)。
  7. 用户空间的程序无法直接执行内核代码。它们不能直接调用内核空间的函数,因为内核驻留在受保护的地址空间上。
  8. 系统调用处理程序实际上是一个异常处理程序,靠软中断实现的,它通过引发一个异常来促使系统切换到内核态去执行异常处理程序(系统调用处理程序system_call()),它与硬件体系结构紧密相关。
  9. 在陷入内核空间之前,用户空间进程得先把系统调用号放入相应体系结构CPU中相应的寄存器内,这样系统调用处理程序就可以读取系统调用号,转而去执行相应的程序。
  10. 内核在接收一个用户空间的指针之前,内核必须保证:指针指向的内存区属于用户空间;指针指向的内存在进程的地址空间里;如果是读,内存应该被标记为读,写和执行也如此.
  11. Linux本身提供了一组宏,用于直接对系统调用进行访问。它会设置好寄存器并调用陷入指令。这些宏是_syscalln(),其中n范围为0~6,代表给内核的参数个数。对于每个宏来说,都有2+2n个参数,第一个参数对应系统调用的返回值类型,第二个参数是系统调用的名称,后面的就是按照系统调用参数的顺序排列的每个参数的类型和名称。例如: #define NR_open 5 _syscall3(long,open,const char*,filename,int,flags,int,mode)