目录
二、CPU中断和DMA
三、系统总线
四、用户态和内核态
五、x86架构和arm架构
六、SMP和NUMA架构
七、设备驱动程序
八、文件系统
一、系统调用
计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同时运行的多个进程都需要访问这些资源,为了更好的管理这些资源进程是不允许直接操作的,所有对这些资源的访问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call)。除了提供访问硬件资源的能力外,系统调用还可以用于进程控制,用户控制等系统管理功能,即系统调用是操作系统面向应用程序提供的用于与操作系统本身交互的接口。
系统调用的种类和实现由操作系统决定,底层依赖于硬件的驱动程序接口,即通过系统调用屏蔽访问底层硬件的实现。应用程序不应该直接使用系统调用,因为系统调用的使用方式与操作系统本身强绑定,而应该使用标准函数库,由标准函数库封装对系统调用的实现。因为标准函数库的实现依赖于系统调用,所以不同的平台如windows,linux都有对应的标准库函数和对应的编译器。
参考: Linux系统调用详解(实现机制分析)--linux内核剖析(六)
系统调用概念
CPU在执行完当前正在执行的指令之后,检测到从CPU外部发送过来的或者内部产生的一种特殊的信息,并且可以立即对所接受到的信息进行处理,这样的信息,我们就称为中断信息。按照中断信息的来源可以分为软中断和硬中断,软中断是在CPU执行过程中产生的,如应用程序异常(如除以0),执行int指令等,软中断主要用于通知CPU终止当前指令序列的执行,比如用户通过系统调用读取文件时需要先发送中断指令,CPU接受中断指令后会保存当前进程的上下文,然后给硬件发送读取文件的指令,然后CPU执行其他的进程;再比如当前进程的CPU时间分片用完了,就会由定时间触发一个软中断通知CPU终止对当前进程的处理,由调度器选择其他的进程执行。硬中断指的由CPU的外部设备如键盘,网卡,鼠标等产生的,硬中断主要用于通知CPU硬件的任务已经执行完了,比如磁盘读取文件,文件读取到内存以后就会发送中断指令给CPU,CPU接受该指令后调用之前注册的中断处理程序将读取文件的内存地址告诉最初的调用方。硬中断主要是为了解决硬件执行任务远远慢于CPU,通过硬中断这种通知方式将CPU和硬件独立开。
CPU中断绝大部分时候会引发进程的上下文切换,即需要保存当前进程的执行环境,然后载入下一个即将运行的进程的执行环境,其性能开销较大,因此可以通过中断率或者上下文切换次数优化应用程序,提升应用性能。
中断是指一种重要的外设与CPU数据交换的方式,因为需要进行断点和现场的保护和恢复,浪费了很多CPU的时间,适合少量数据的传送。DMA(Direct Memory Access,直接存储器访问)是指外部设备不通过CPU而直接与系统内存交换数据的接口技术,适合批量数据传送,整个过程主要由DMA控制器完成。DMA传输整体分为三个过程:第一,预处理,由CPU完成一些必要的准备工作,如向DMA控制器的有关寄存器置初值,设置传送方向、启动该设备等。然后等到I/O设备准备好发送的数据(输入情况)或接受的数据(输出情况)时,I/O设备向DMA控制器发送DMA请求,再由DMA控制器向CPU发送总线请求(统称为DMA请求),用以传输数据;第二,数据传送,传输过程中内存为该DMA通道分配内存空间(即DMA缓冲区),整个过程完全由DMA(硬件)来控制的;第三,后处理,DMA控制器向CPU发送中断请求,CPU执行中断服务程序做DMA结束处理,包括检验送入主存的数据是否正确,测试传送过程中是否出错等。
参考:CPU的内部的中断
详解操作系统中断
性能分析_linux服务器CPU_中断
DMA之理解
DMA
总线是指多个设备之间传输数据的通信线路,在物理层面总线通常是由多条通信线路组成,每条线路只能传递0或者1的信号,即1bit的数据。假如总线有N条通信线路,则其总线位宽为N,单条线路每秒传输信号的次数称为总线的工作频率,总线每秒能够传输的数据量称为总线的带宽,等于总线工作频率乘以总线位宽,单位是bit/s,除以8就是byte/s。
连接计算机主要设备如CPU,内存,磁盘等的总线称为系统总线,如Intel公司提出的PCI总线。按照总线的功能或者传输的数据种类划分,总线可以分为数据总线,控制总线和地址总线,按照总线的传输方式可以划分为串行总线和并行总线,连接设备的类型和使用场景不同就会由不同规范标准的总线,如QPI总线是处理器互联,Memory总线是处理器和内存互联。
数据总线顾名思义就是传输需要处理的数据的总线,在CPU和其他设备间双向传输,数据总线的位宽通常和CPU的位宽保持一致,CPU的位宽是指CPU一次运算能够处理的数据量,现代PC机CPU位宽通常是64位,数据总线的位宽直接影响数据处理的吞吐量。控制总线用来传送控制信号、时序信号和状态信息等,同数据总线双向传输。地址总线用于传送CPU发出的地址信息,是单向的。内存或者高速缓存对CPU而言相当于一个数组,数组元素就是一个byte,而数组索引就是访问地址。地址总线的位宽决定了寻址的范围,位宽为N,其寻址范围是0 - 2^N,而寻址最大范围决定了可用了最大的内存空间,以32位位宽为例,其最大内存空间为2^32/1024/1024=4096M,即4GB。因为地址信息由CPU发出,所以地址总线的位宽与CPU的位宽一致。
串行总线是指设备间数据传输通过串行的方式传输,即只有一根传输线,并行总线是有多根传输线并行传输,理论上并行总线的传输效率更高,但是受到并行传输时信号干扰,信号同步等问题影响,实际使用串行总线,通过大幅提高总线工作频率的方式大幅提高传输效率,如常见的USB总线。
参考: 计算机总线-1-baike
总线概述及常见总线
为什么说串行比并行快
用户态和内核态本质上是CPU的特权级别,比如Intel的CPU将特权级别分为4个级别:RING0,RING1,RING2,RING3,Linux将RING0作为内核态,RING3作为用户态。处于内核态下的进程可以访问计算机所有的资源,处于用户态下的进程只能访问有限的资源,区分内核态和用户态就是为了确保操作系统本身的安全和可靠,避免危险指令和敏感资源被非法访问,比如系统调用只能在内核态下执行。
进程可以在内核态和用户态之间来回切换,从用户态切换到内核态有两种方式:CPU中断、运行时异常,其中CPU中断包括执行系统调用前发送int指令触发的软中断和硬件执行完任务触发的硬中断,切换时先将用户态进程的上下文环境保存到内存,然后将待执行的内核代码加载到内核栈,每个进程会有独立的内核栈,然后执行系统调用,执行完成后自动切换回用户态,将之前保存的上下文环境重新加载到进程的栈帧,即每次切换都是上下文切换,与普通进程切换的上下文切换相比,用户态和内核态切换多了一个用户态下方法参数传递到内核态系统调用,系统调用的结果回传至用户态,因为内核态和用户态的地址空间是独立的,内核代码不能识别用户态下的内存地址即变量指针,只能通过寄存器传递。两者能够来回切换的基础是所有进程共享内核空间。
参考:用户态与内核态
用户态和内核态的理解和区别
用户态切换到内核态
x86架构和arm架构并不是CPU底层实现的硬件规范而是CPU对外提供服务的指令集,寄存器,输入输出模型规范,CPU指令就是具体的机器码,机器语言,寄存器规范指的是寄存器的种类,个数和状态,输入输出模型是CPU引脚的输入输出规范,具体的CPU指令和寄存器使用可以参考对应架构的汇编语言。x86指令集是CISC(Complex Instruction Set Computers,复杂指令集计算集)的代表,主要应用于PC,服务器和大型机等处理器,arm指令集是RISC(Reduced Instruction Set Computers,精简指令集计算集)的代表,主要应用于移动端和嵌入式等处理器。两者的设计思想是相反的,CISC是由CPU提供复杂功能的指令从而降低其上层程序开发的难度,提升复杂逻辑下系统性能,问题是复杂指令的实现增加了CPU整体的设计难度并影响执行效率,而RISC则是由CPU提供最常用的简单的指令,复杂指令由编译器将其拆分成多个简单指令实现,这样降低了CPU的设计难度,提升了常用指令的执行效率,但是增加了上层程序的复杂性,降低了复杂逻辑下系统效率。现代CISC处理器和RISC处理器在发展的过程中彼此取长补短,逐步走向融合。两者的区别如下:
重点关注可访存指令的差异,具体来说CISC指令可以直接读写内存或者寄存器,支持多种寻址方式,而RISC指令则只能读写寄存器,通过取数/存数指令读写内存,支持的寻址方式较少 。
指令集本身也是在不断发展的,通过不断追加新的指令实现,之前的指令保持不变,从而保持向前兼容。指令集架构的32-bit或64-bit决定了对应处理器的位数,处理器的位数决定了与处理器配套的地址总线,数据总线的位宽,现代CPU通常都是64位的,linux上可通过lscpu命令查看。
参考: ARM(RISC)和x86(CISC)的技术差异
CISC和RISC的区别
处理器、指令集架构和操作系统——32-bit与64-bit
MIPS、ARM、X86三大架构
SMP(Symmetric Multi-Processor)是指对称多处理器结构,服务器中多个CPU对称工作,无主次或从属关系,各CPU共享相同的物理内存,系统总线,IO设备等。每个 CPU访问内存中的任何地址所需时间是相同的,因此SMP也被称为一致存储器访问结构(UMA:Uniform Memory Access)。随着处理器个数的增加,对总线的竞争越来越严重,总线成为SMP继续扩展的瓶颈。为了解决这个问题,产生了NUMA(NON-Uniform Memory Access)非一致性访问架构,具体来说将CPU平均划分为若干个Chip(不多于4个),每个Chip有自己的内存控制器及内存插槽,成为本地内存,Chip间通过互联模块访问,同一Chip内的CPU访问本地内存很快,时间一致,但是访问其他Chip的本地内存(Remote Access)就比较慢。NUMA架构有效结合了SMP架构易编程性和MPP(大规模并行)架构易扩展性的特点,较好解决了SMP系统的可扩展性问题,在一个物理服务器内可以支持上百个CPU,已成为当今高性能服务器的主流体系结构之一,如HP的Superdome、SUN15K、IBMp690等。MPP架构就是通常的集群服务模式,多台物理上独立的服务器通过程序层面的协调配合对外提供统一服务。
Linux从2.6开始支持NUMA架构,但是存在因为CPU亲和策略导致的内存分配不平均等问题而没有大规模应用,尚在发展和优化中。为了兼容NUMA相关代码,在默认不开启NUMA支持的情况下,Linux将内存视为一个单独的Chip。
参考: numa详解
NUMA架构的CPU -- 你真的用好了么?
设备驱动程序充当了硬件和软件之间的枢纽,驱动程序屏蔽同底层硬件的交互细节,对软件提供统一的调用接口,这些接口由操作系统事先定义并制定实现的标准规范,接口和实现规范合称为驱动架构。Linux内核提供了基础的设备驱动程序,如果需要硬件设备性能最大化则需要在此基础上做定制开发。
Linux将所有设备都当做文件处理,分为两种类型,字符设备和块设备:字符设备提供连续的数据流,应用程序可以顺序读取,通常不支持随机存取,如键盘等;块设备支持随机存取,读写数据的单位通常是一个块(512byte),如硬盘等;两者最大的差异是其驱动程序对外的接口不一样。设备文件由VFS(virtual file system,虚拟文件系统)管理,用主设备号标识设备驱动程序,从设备号标识同一设备驱动程序下的不同硬件,如同一个磁盘驱动程序下的多块磁盘。当应用程序通过C库函数调用系统调用操作设备时,系统调用会通过VFS找到对应设备文件,然后调用其驱动程序完成设备操作。
设备驱动程序由C/C++语言开发,属于内核代码,只能在内核态下执行。设备驱动程序直接操作设备控制器的寄存器,设备控制器就是类似于CPU的集成电路芯片,大概流程如下:驱动程序将操作参数和指令写入寄存器,由设备控制器将寄存器中值转换成高低电平信号,推动硬件设备完成相应操作,然后从寄存器读取操作结果,将结果由内核空间拷贝到用户空间。调用关系如下图:
参考:Linux下PCI设备驱动程序开发
嵌入式Linux驱动开发(二)——字符设备驱动之控制LED
初次使用磁盘时需要对磁盘做分区,磁盘分区是将磁盘划分成主分区和扩展分区,并选择一个主分区作为活动分区,然后对各分区格式化,即在分区内初始化指定的文件系统,不同的分区可以选择不同的文件系统。所有的分区信息和操作系统的启动加载器都记录在磁盘的第一个扇区中,通常是512字节,其存储方式有两种MBR(Master Boot Record)和GPT(GUID Partition Table),MBR与BIOS引导配合使用,GPT与UEFI引导配合使用,后者是新标准。操作系统在磁盘格式化完成后会写入活动分区,启动时会从MBR或者GPT中找到启动加载器,通过它将操作系统加载到内存并启动。
扩展分区是MBR中的概念,MBR中最多只能有4个主分区,扩展分区是一个特殊的逻辑上的主分区;GPT支持无限多个主分区,但操作系统支持的分区数量有限。扩展分区下可以包含多个逻辑分区,每个逻辑分区包含到下一个逻辑分区的指针,第一个逻辑分区的指针保存在MBR中。如下图,F,G,H是主分区,I,K,J是逻辑分区,组合成一个扩展分区。
文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。对存储设备的使用者而言,文件系统就是存储设备的一个抽象,使用方无需关心存储设备的类型,存储设备是如何工作的,文件在存储设备中是如何存放的等等细节。windows下,主要有FAT16 、FAT32 、NTFS文件系统;Linux下,主要EXT2、3、4和swap、Tmpfs文件系统。文件系统实现原理大概如下,每个文件和文件夹都对应一个Inode的数据结构,Inode记录这个文件的各种属性以及包含文件内容的数据块,一个文件通常由多个数据块组成,Inode包含一张表来记录所有的数据块的地址;每个文件夹都包含一张Inode的索引表,可以通过文件名找到对应文件的inode节点,这种索引表和inode节点本身都存放在数据块中。以读取文件为例,大概过程如下:
文件系统从上到下分为用户层、VFS层、文件系统层、缓存层、块设备层、磁盘驱动层、磁盘物理层,如下:
参考:硬盘分区形式(MBR、GPT)、系统引导、文件系统、Inode和Block
linux文件系统详解