一天一个linux内核知识点

一天一个linux内核知识点

本文章的作用是大致了解了解linux内核的运行机制,通过问题的形式帮组作者回忆知识点
本文章知识作者对于知识点的一个自己的总结,需要学习的可以参考原文本:https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzk0MjE3NDE0Ng==&action=getalbum&album_id=2123743679373688834&scene=173&from_msgid=2247502181&from_itemidx=1&count=3&nolastread=1#wechat_redirect

POSIX标准

POSIX(Portable Operating System Interface,可移植操作系统接口)是一组定义了操作系统接口的标准。它最初由IEEE(Institute of Electrical and Electronics Engineers,电气和电子工程师学会)开发,并在1988年被采纳为国际标准(ISO/IEC 9945)。POSIX标准的目的是为了提供一个可移植的操作系统接口,使得软件开发人员可以在不同的操作系统上编写可移植的应用程序。
POSIX标准定义了一系列的系统调用、库函数和命令行工具,涵盖了文件操作、进程管理、线程、信号处理、网络通信等方面的功能。通过遵循POSIX标准,开发人员可以编写与操作系统无关的代码,从而提高代码的可移植性和可重用性。
POSIX标准主要适用于类Unix操作系统,如Linux、macOS和BSD等。它为这些操作系统提供了一致的接口,使得应用程序可以在不同的类Unix系统上运行而无需进行大量的修改。

启动部分

BIOS的作用是什么呢?
自己理解的部分:
1、加载第一个扇区(512个字节的数据)的数据到内存的某一个地方。
2、对内存进行初步的规划,设置数据段,代码段和堆栈段的基地址和大小。
3、加载启动程序和系统到内存。其中硬盘的2-4扇区为启动程序。
4、读取计算机一些硬件的信息,并保存在计算机中某些位置

BIOS(基本输入/输出系统)是计算机系统中的一种固件,它位于计算机的主板上。BIOS具有以下几个主要作用:
启动计算机:当计算机开机时,BIOS是第一个被加载和执行的软件。它负责初始化和检测硬件设备,确保它们正常工作,并为操作系统的启动做准备。
提供硬件控制:BIOS提供了与计算机硬件交互的接口。它包含了与主板、处理器、内存、硬盘、显卡等硬件设备通信的指令集。操作系统和应用程序可以通过BIOS来访问和控制这些硬件设备。
提供系统设置:BIOS还提供了一些系统设置选项,例如日期和时间、启动顺序、硬件配置等。这些设置可以通过BIOS界面进行修改,以满足用户的需求。
处理异常情况:当计算机遇到硬件故障或配置错误时,BIOS可以检测并处理这些异常情况。它可以发出警报、显示错误信息或尝试修复问题。
总的来说,BIOS是计算机系统的基础软件,它提供了启动计算机、控制硬件设备和提供系统设置的功能。它在计算机的启动过程中起到关键的作用,并为操作系统和应用程序提供了与硬件交互的接口。

setup的作用是什么呢?
自己理解:
启动程序的作用 1、读取光标信息?
2、关中断
3、设置自己的中断向量表
4、将操作系统镜像加载到内存中覆盖掉BIOS代码
疑问?这里又重新对内存作了管理吗?
5、开启分页机制并且跳转到main函数

gpt的回答:

计算机中的启动程序(也称为引导程序)的作用是在计算机开机时加载和执行操作系统。它是计算机启动过程中的第一个可执行程序。
启动程序的主要作用包括:
加载操作系统:启动程序负责从存储设备(如硬盘、固态硬盘或光盘)中读取操作系统的核心文件,并将其加载到计算机的内存中。操作系统是计算机的核心软件,它管理和控制计算机的各种硬件和软件资源。
初始化系统环境:启动程序还负责初始化计算机的硬件设备和系统环境。它会检测和配置处理器、内存、硬盘、显卡等硬件设备,确保它们正常工作。此外,启动程序还会设置一些系统参数和环境变量,为操作系统和应用程序提供正确的运行环境。
启动顺序管理:启动程序还管理计算机的启动顺序。它确定哪个设备中的引导扇区(包含启动程序)将首先被加载和执行。通常,计算机会按照预设的启动顺序依次尝试从不同的设备(如硬盘、光盘、USB驱动器)中加载启动程序,直到成功为止。
错误处理:启动程序还负责处理启动过程中可能出现的错误情况。例如,当找不到操作系统文件、硬件故障或配置错误时,启动程序可以发出警报、显示错误信息或尝试修复问题。
总的来说,启动程序在计算机的启动过程中起到关键的作用,它加载和执行操作系统,初始化系统环境,并管理启动顺序。它确保计算机能够正确启动,并为操作系统和应用程序提供正确的运行环境。

什么是分段管理和分页管理呢?
分段管理是通过段描述符实现的,将段描述符存储到启动程序中。之后在head.h中重定向段基地址和中断向量表。
而分页管理则是由页目录和相应的页表加上一系列复杂的转换合成的。
他的地址转化步骤如下:
逻辑地址->线性地址->物理地址;

来看看AI的解释:
分段管理(Segmentation Management):
在分段管理中,内存被分成若干个大小不等的段(segments),每个段对应着一个逻辑单位,比如程序的代码段、数据段、堆栈段等。每个段的大小可以根据需要进行设置,不同的段可以有不同的大小。程序在运行时,可以根据需要申请一段连续的内存空间,然后将这些内存空间连接成一个段,以满足程序的要求。这种方法适合于处理不规则大小的内存需求,但容易产生外部碎片。

分页管理(Paging Management):
在分页管理中,内存被划分成固定大小的页(pages),而程序的逻辑空间也被划分成固定大小的页框(page frames)。当程序运行时,逻辑页会被映射到物理页框上。这种方法的好处是消除了外部碎片,但可能会引发内部碎片,因为程序的逻辑页大小不一定与物理页框大小完全匹配。

分段和分页管理是如何实现的呢?
首先一页的寻址大小是12位也就是4k。一个页表目录的大小是10位也就是1k,所以4个页表目录所管理的大小也就是16M。而这个页表管理则放在了内存的开头0x00000000的地方。

这段代码是在转到main函数之前跳转的。通过设置一些基础的参数实现的。当然会有一个寄存器Cr3一直记录页表的首地址。

分段机制设置出来是为了什么呢?
分段机制的设计初衷是为了解决程序的内存管理问题。在早期的计算机系统中,程序的内存需求通常是不连续的,而传统的连续内存分配方式无法满足这种需求。因此,分段机制被引入以解决这个问题。
分段机制的设计初衷包括以下几个方面:
内存利用率:分段机制可以将程序的内存空间划分为多个较小的段,每个段可以根据程序的需求进行分配。这样可以提高内存的利用率,避免出现大量的内存碎片。
程序的逻辑结构:分段机制可以反映程序的逻辑结构,将程序按照模块、函数或数据结构进行划分。这样可以使程序的组织更加清晰,易于维护和理解。
内存保护:分段机制可以为每个段设置访问权限,防止程序越界访问其他段的内存。这样可以提高系统的安全性,防止恶意程序对系统造成损害。
动态加载和链接:分段机制可以支持动态加载和链接,即在程序运行过程中根据需要加载和链接额外的段。这样可以实现模块化的程序设计,提高程序的灵活性和可扩展性。
综上所述,分段机制的设计初衷是为了提高内存利用率、反映程序的逻辑结构、实现内存保护以及支持动态加载和链接,从而满足程序的内存管理需求。

进程管理部分

进程调度是怎么开始的呢?
1、配置gdt中的TSS(上下文环境)和ldt(代码段、数据段)
2、设置时钟中断0X20(调度时间基准)和系统中断0x80(系统调度)
3、初始化了一个结构为 task_struct 的数组,未来这里会存放所有进程的信息,并且我们给数组的第一个位置附上了 init_task.init 这个具体值,也是作为未来进程 0 的信息。
进程是如何被创建的呢?

进程调度又是怎么回事呢?
切换时机:首先需要了解的是,在linux0.11内核中,滴答定时器作为进程切换的节拍,每隔10ms发出一个时钟中断,然后判断程序是否执行在用户态还是内核态,如果执行在内核态,则程序是不可以被打断的,反之,若是执行在用户态,首先看程序是否已经用完时间片,如果没有则继续执行程序,反之则调用schedule()进行程序切换。

进程切换:也就是上下文切换,保存当前任务执行的上下文,并且将新任务的上下文加载到寄存器中。当然这里涉及全局描述符GDT和tss啥的就略过了。

进程管理的数据结构是什么呢?
struct task_struct 主要包含以下内容:其中保存着用于控制和管理进程的所有信息。主要包括进程当前运行的状态信息、信号、进程号、父进程号、运行时间累计值、正在使用的文件和本任务的局部描述符以及任务状态段信息。
关于tss的补充:在这里插入图片描述
着其中就是储存了各个寄存器的值,其中cr3的话就是页表寄存器,通过不同的页表结构,能够将相同的线性地址转换到不同的物理地址上。

进程是如何被赋值的呢?
首先把父进程的task结构体完全复制给儿子,之后申请一页4k的内存给儿子进程,并将其task结构体的信息保存在申请的内存的最底端,最后将内核的堆栈(当进程陷入内核使用)设置为申请内存的最顶端。
当然,这里最难理解的就是进程的内存规划问题:
1、先将原进程的LDT项和页表项进行拷贝
2、根据进程的PID号,在线性内存地址空间中分配64M的地址空间。
在这里插入图片描述
大致分配下来是这样的,当然只有在需要真正用到物理地址空间时才会真正去申请内存,否则都是和父进程公用一个物理内存。(这里涉及到写时复制技术,就不深究了)

缓冲区

1、缓冲区有什么作用呢?
作为缓冲区和块设备之间的桥梁,当需要访问块设备时需要先访问缓冲区中是否有相同的数据弱国有的话则直接进行读取,没有的话则直接将块设备的内容先加载到缓冲区,在加载到内存。
目的:加快程序的读写速度,有一些常用的内容直接存在缓冲区中,防止重复遍历造成的资源浪费。

来看看chatgpt的说法:
缓冲区(Buffer)在计算机科学中起着重要的作用。它是一块临时存储区域,用于在不同速度的设备之间传输数据时进行数据的临时存储和调整。
缓冲区的主要作用有以下几个方面:
数据传输:缓冲区可以在数据发送和接收之间起到中转的作用。当发送方和接收方的速度不匹配时,缓冲区可以暂时存储数据,以便在合适的时机进行传输。
提高效率:缓冲区可以减少对主存或外部设备的频繁访问,从而提高数据传输的效率。通过将数据暂时存储在缓冲区中,可以减少对主存或外部设备的访问次数,从而节省时间和资源。
平衡数据流:缓冲区可以平衡数据流,使得发送方和接收方之间的数据传输更加平滑。当发送方和接收方的速度不一致时,缓冲区可以调整数据的流动速度,以避免数据丢失或传输错误。
提供临时存储:缓冲区可以提供临时存储空间,用于存储临时数据或处理数据。在许多计算任务中,缓冲区可以作为临时存储区域,用于存储中间结果或临时变量,以便后续的处理和计算。
总的来说,缓冲区在数据传输和处理过程中起到了重要的作用,可以提高效率、平衡数据流,并提供临时存储空间。
2、缓冲区又是怎么进行管理的呢?
1)、先规划内存的大小
2)、使用buffer_head这个结构体对内存进行管理,有缓冲块的大小(1024),并且通过链表对这个结构体进行存储(双向链表),并且hash表存储这个结构体(cpu方便查询),具体的规划表可以见下图。

在这里插入图片描述

内存规划

在不同得阶段是如何设置内存的呢?
启动部分的内存规划就不讨论了,讨论一下在进入main.c之前的内存规划吧,首先把整个内存分为了内核程序,缓冲区以及主内存。这段代码就是在程序最开始的时候设计的。
在这里插入图片描述
这里使用以下数据结构来管理空白内存,其中内存以4k为单位进行申请和释放。
static unsigned char mem_map [ PAGING_PAGES ] = {0,};;
而申请内存则使用函数unsigned long get_free_page(void),他会在数组mem_map中寻找一个空白页,并标记为已经使用,最后返回其基地址。

硬盘管理部分

为什么需要有文件系统?

答:在Linux系统中,文件系统同样扮演着重要的角色。以下是一些需要文件系统的原因:
存储和组织数据:文件系统在Linux系统中用于存储和组织文件和数据。它提供了一种层次结构的方式来组织文件和目录,使用户能够轻松地查找和访问所需的文件。
文件访问和管理:文件系统提供了一组工具和命令,使用户能够对文件进行访问、创建、复制、移动、删除等操作。它还提供了文件权限和所有权管理机制,以确保只有具有适当权限的用户才能访问和修改文件。
设备和驱动程序管理:文件系统在Linux系统中也用于管理设备和驱动程序。在Linux中,设备通常被表示为文件,通过文件系统可以访问和管理这些设备。例如,硬盘驱动器、USB设备和网络设备等都可以通过文件系统进行管理。
数据持久性:文件系统确保数据在计算机关机或重启后仍然可用。它将数据写入存储设备(如硬盘或固态驱动器),以便在需要时可以重新加载和使用。
文件共享和网络传输:文件系统在Linux系统中支持文件共享和网络传输。通过网络文件系统(如NFS)或文件传输协议(如FTP或SCP),用户可以在不同的计算机之间共享和传输文件。
总之,文件系统在Linux系统中起着至关重要的作用,它提供了一种有效的方式来存储、管理和组织数据,并支持文件访问、设备管理、数据持久性以及文件共享和网络传输等功能。

如何将硬盘的数据读到内存的呢
1、首先进程管理结构体中有一个文件描述符数组:filep[20],储存着打开的文件描述符。
2、在系统中本来也有一个系统文件表file_table,里面存储的是控制文件的结构体file,在读取inode号就可以查找到块设备。
在这里插入图片描述

如何运行一个字符设备得呢?

文件系统

一个进程是如何读取一个硬盘上的文件的呢?

内核态与用户态

什么是内核态,什么是用户态?
内核态(也称为特权模式或系统模式)是操作系统内核运行的模式。在内核态下,操作系统具有最高的权限和访问系统资源的能力。在这种模式下,操作系统可以执行特权指令,访问所有的内存和设备,并且可以执行特殊的操作,如修改中断向量表和处理异常。
用户态(也称为非特权模式或用户模式)是应用程序运行的模式。在用户态下,应用程序只能访问受限的资源,并且不能直接访问操作系统的内核功能。应用程序只能执行非特权指令,并且对于某些敏感的操作,如访问硬件设备或修改系统配置,需要通过系统调用来请求操作系统的帮助。

简单的理解:访问块设备,字符设备等都需要内核态,而用户态则不行这种区分可以确保操作系统的稳定性和安全性,同时允许应用程序在受控的环境中运行。

用户态和内核态是如何区分的?
通过段选择子,和段描述符中的一些特殊的寄存器规定的,也就是区分了特权模式和非特权模式。(这里也是由分段保护机制所完成的)

应用程序如何通过系统调用调用内核函数?
首先在fn_ptr sys_call_table[]这个数据结构中定义了许多的内核函数,然后通过软中断:int80h,调用system_call,在通过这个调用sys_call_table[2]的中断函数sys_fork。
在这里插入图片描述

shell程序

如何加载跟文件系统的呢?
1、将磁盘的超级块的信息读入 struct super_block * p中
2、就是将超级快块的信息读入到内存中
3、把超级块作为进程1 的根目录和当前工作目录
4、记录位图和块图信息
到这里 就是把超级块作为root目录,由于超级块也是文件系统的索引,作为根目录很合适。

终端是什么?

shell是如何运行的呢?这里只针对最开始的shell是怎么执行的
fork and execve程序
fork就是创建进程。
execve就是跳转到脚本文件执行,其执行代码的思路大致如下:
1 检查文件类型和权限等
2 读取文件的第一块数据到缓冲区
3 脚本文件与可执行文件的判断
4 校验可执行文件是否能执行
5 进程管理结构的调整
6 释放进程占有的页面
7 调整线性地址空间、参数列表、堆栈地址等
8 设置 eip 和 esp,完成摇身一变

只有引发缺页中断,将剩余的脚本文件从硬盘加载到内存中。

Linux是如何访问驱动设备的呢?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值