编辑
2023-04-29
Linux
00
请注意,本文编写于 634 天前,最后修改于 630 天前,其中某些信息可能已经过时。

目录

Linux系统结构
Kernel
系统调用接口
举例ret2syscall
System Call interface
参考
内存管理 Memory management(x86架构-32位Linux系统)
虚拟内存
内存分区
参考
页与页框与页表
进程和内存
内核空间
直接映射区
高端内存线性地址空间:
动态内存映射区
永久内存映射区:
固定映射区
简析VFS
简介
原理
参考
进程管理(completely fair scheduler)
参考:
Linux shell

Linux系统结构

image

Linux系统结构一般分为四部分:

  • kernel
  • shell
  • FILE system
  • application

image-20230420204008612

Kernel

Linux 内核由如下几部分组成:内存管理、进程管理、设备驱动程序、文件系统和网络管理等。如图:

image-20230420204259268

系统调用接口

为了使用户有良好的运行环境,当用户需要调用系统内核函数时,操作系统就会将系统调用接口提供给用户使用。

而系统调用的作用就是将应用程序的请求给系统内核,调用相应的系统内核函数。Linux系统调用,包含了大部分常用的系统调用和由系统调用派生出的函数。

举例ret2syscall

这里的在linux-x86上的系统调用是通过int 0x80实现,通过系统调用号区分函数入口:

  1. 应用程序调用库函数(API);
  2. API 将系统调用号存入 EAX,然后通过中断调用使系统进入内核态;
  3. 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);
  4. 系统调用完成相应功能,将返回值存入 EAX,返回到中断处理函数;
  5. 中断处理函数返回到 API 中;
  6. API 将 EAX 返回给应用程序。

System Call interface

API(Application Programming Interface)又称为应用程序接口。通过该接口用户程序员可以间接的访问到系统硬件和操作系统资源。操作系统的主要作用之一就是把系统硬件和操作系统资源进行封装并对上层用户进行屏蔽,防止用户有意无意的对系统造成破坏。操作系统就像一个保护壳一样保护系统资源不被外界破坏。因此,当用户需要对系统资源进行访问的时候,就必须通过操作系统向用户提供的接口才能实现用户对系统资源的访问,取得内核的服务。

API一般以函数定义的形式出现,如read()、malloc()、abs()等。但API并不需要和系统调用一一对应,它们之间的关系可以是一对一、一对多、多对一或者无关系。例如read()接口就和read系统调用对应,而abs()作用是求绝对值,不需要任何系统调用。而且一般API主要是通过C函数库来实现。

而ret2syscall中int 0x80 是一种用于在 Linux 系统中进行系统调用的方式,它通过向处理器发出中断信号,使得程序从用户态切换到内核态,以请求内核提供相应的服务。而 System Call Interface (SCI)是操作系统提供的 API,用于执行从用户空间到内核空间的函数调用,从而实现用户程序对内核中功能的调用。

int 0x80 的实现需要依赖于 SCI 接口,在早期的 Linux 版本中,其中的一些系统调用就是通过 int 0x80 来实现的。在这个过程中,int 0x80 这条指令会触发中断,进而执行 SCI的相关代码,将程序从用户态切换到内核态,完成系统调用的过程。

因此,int 0x80 和 SCI 之间存在着密切的关系,可以说是两种不同层面上的实现方式。在较新版本的 Linux 中,int 0x80 已经逐渐被其他更加高效的实现方式所替代,但 SCI 接口作为操作系统提供的核心接口之一,一直扮演着非常重要的角色。

参考

(系统调用 - 维基百科,自由的百科全书 (wikipedia.org))

((1条消息) 系统调用接口_xiaobaiyuan_bk的博客-CSDN博客)

(2.4. 系统调用接口 — 计算机系统基础 (jmu.edu))

内存管理 Memory management(x86架构-32位Linux系统)

因为物理空间中计算机内存是极为有限的,而实际使用中对计算机的各种操作都会占用计算机的内存。以下是主要问题:

  • 内存使用效率低:无法解决多任务并发时物理内存不够用的情况
  • 地址空间不隔离:不同的操作之间可能会对物理内存中同一块地址进行操作,这就容易导致崩溃。
  • 地址不明确,未使用空间的地址不明确

虚拟内存

引入一个中间层(即虚拟内存)对进程地址和物理地址进行隔离。

内存分区

Linux系统对内存结点进行分区:

  • DMA:直接内存访问区,通常为物理内存的起始16M;主要供I/O外设使用,无需CPU参与的外设和内存DMA;
  • Normal:从16M到896M内存区;内核可以直接使用
  • Hight memory:896M以后的内存区;高端内存,内核不能直接使用
text
`DMA`:0~16MB内存页框,可由老式基于ISA设备通过DMA使用,直接映射到内核的地址空间。是一种计算机系统中常用的数据传输方式,它可以让设备在不占用CPU时间的情况下,直接访问内存,实现高速数据传输。 在数据传输量大、速度要求高的场景中, DMA传输过程中,通常需要使用一个特殊的硬件设备——DMA控制器。(这里指不通过CPU来实现外设与数据交换的控制器,硬件)
参考

(关于DMA(Direct memory access)比较通俗浅白的理解 - 腾讯云开发者社区-腾讯云 (tencent.com))

Linux之DMA详解


低于869MB界限为:low memory,反之,高于869MB则称为high memory。

如图:

image-20230421202851960

页与页框与页表
  • 页:将进程分配的虚拟地址空间划分的块,对应的大小就叫页面大小。
  • 页框:将内存物理地址划分的块。页和页框二者一一对应,一个页放入一个页框,(理论上)页的大小和页框的大小相等。
  • 页表:操作系统维护的页表,页表记录了每一对页和页框的映射关系。

三者关系:

image-20230423205604043

页面大小:4kb。页表项大小:4B。32位虚拟地址可以表示的进程大小2^32为4GB。

页面面数为:2^20页,所以页表就需要4MB空间

进程和内存

用户空间被划分为5个不同的内存空间:text,data,BSS,heap,stack,

  • text(代码段):代码段用于存放可执行操作指令,只读,不可执行。
  • data(数据段):存放可执行文件的已初始化的全局变量。
  • Bss:程序中的未初始化全局/局部变量/
  • heap(堆):用于存放进程中的被动态分配的内存段,是由用户调用malloc等函数向操作系统申请空间(一块空间被称作一个chunk),当这一块chunk被用户使用free释放掉之后,这一块申请的空间不会被返还给系统,而是会将它放入bins链中,为后续的调用空间提高效率。
  • stack(栈):栈是用户存放程序临时创建的局部变量的一块区域(注意:这里并不包含static申明的变量,其在data段)。每有一个函数被调用都会在stack中开辟一块新的栈帧,在调用函数之前会先将所调函数的参数入栈,然后将主调函数的ret_addr和主调函数的ebp地址依次入栈(这里是为了在执行完被调函数后恢复原本的栈帧,以保持栈平衡),最后才会执行被调函数。

内核空间

image-20230423213022209

直接映射区

直接映射区 Direct Memory Region:从内核空间起始地址开始,最大896M的内核空间地址区间,为直接内存映射区。

直接映射区的896MB的「线性地址」直接与「物理地址」的前896MB进行映射,也就是说线性地址和分配的物理地址都是连续的。内核地址空间的线性地址0xC0000001所对应的物理地址为0x00000001,它们之间相差一个偏移量PAGE_OFFSET = 0xC0000000

该区域的线性地址和物理地址存在线性转换关系「线性地址 = PAGE_OFFSET + 物理地址」也可以用 virt_to_phys()函数将内核虚拟空间中的线性地址转化为物理地址。

高端内存线性地址空间:

内核空间中896MB到1GB空间被称为高端内存线性地址空间。前面提到0-896MB是直接映射,也就是和物理空间是一样连续的,但是实际上目前pc里的内存肯定都大于1GB,所以我们总不能后面的也都直接映射吧,这时候这后面的高端内存线性空间就得发挥作用了。他被划分为三块区域(这里只适用于32bit):

  • 动态内存映射区
  • 永久内存映射区
  • 固定映射区
动态内存映射区

vmalloc Region 该区域由内核函数vmalloc来分配,特点是:线性空间连续,但是对应的物理地址空间不一定连续。vmalloc 分配的线性地址所对应的物理页可能处于低端内存,也可能处于高端内存。

永久内存映射区:

Persistent Kernel Mapping Region 该区域可访问高端内存。访问方法是使用 alloc_page (_GFP_HIGHMEM) 分配高端内存页或者使用kmap函数将分配到的高端内存映射到该区域。

固定映射区

Fixing kernel Mapping Region 该区域和 4G 的顶端只有 4k 的隔离带,其每个地址项都服务于特定的用途,如 ACPI_BASE 等。

image-20230423215028506

(手画好累)

简析VFS

简介

虚拟文件系统(Virtual File system)是linux内核的文件子系统之一,它为用户程序提供文件和文件系统操作的统一接口,屏蔽不同文件系统的差异和操作细节。借助VFS可以直接使用open()read()write()这样的系统调用操作文件,而无须考虑具体的文件系统和实际的存储介质。

原理

VFS之所以能够衔接各种各样的文件系统,是因为它抽象了一个通用的文件系统模型,定义了通用文件系统都支持的、概念上的接口。新的文件系统只要支持并实现这些接口,并注册到Linux内核中,即可安装和使用。

举个例子,比如Linux写一个文件:

text
int ret = write(fd, buf, len);

调用了write()系统调用,它的过程简要如下:

  • 首先,勾起VFS通用系统调用sys_write()处理。
  • 接着,sys_write()根据fd找到所在的文件系统提供的写操作函数,比如op_write()
  • 最后,调用op_write()实际的把数据写入到文件中。

image-20230420203000315

参考

进程管理(completely fair scheduler)

参考:

Linux CFS 调度器:原理、设计与内核实现(2023) (arthurchiao.art)

Linux shell

shell的中文意思就是‘壳’,从第一张图中可以看出shell是建立在kernel之上的,shell就相当于kernel的一个接口,用于连接用户与内核空间。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Hyrink

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!