Linux探究之路
文章平均质量分 95
Linux探究之路
Binary Oracle
一名热爱开源和技术的Coder , 开源框架spring committer , golang开源网络库netpoll committer; (脱产备战25考研中,停更一年)
展开
-
Docker容器里进程的 pid 是如何申请出来的?
最后,举个例子,假如有一个进程在 level 0 级别的 pid 命名空间里申请到的进程号是 1256,在 level 1 容器 pid 命名空间里申请到的进程号是 5。那么这个进程以及其 pid 在内存中的形式是下图这个样子的。那么容器在查看进程的 pid 号的时候,传入容器的 pid 命名空间,就可以将该进程在容器中的 pid 号 5 给打印出来了!!转载 2023-03-01 15:48:23 · 349 阅读 · 0 评论 -
你的新进程是如何被内核调度执行到的?
好了,我们把今天的文章的内容总结一下。一个进程从 fork 创建出来到最后真正能获得 CPU 并进行运行,中间有很多的内核逻辑需要处理,我把它分成了这么几个步骤供你更容易地理解。第一,每个 CPU 核都有一个运行队列。为了支持不同的调度需求,运行队列是由实时调度器、完全公平调取器等多种调度器组成。第一,是进程在 fork 的时候会选择自己的调取器,用户进程一般都是用完全公平调度器(fair_sched_class)。转载 2022-12-19 22:34:21 · 427 阅读 · 0 评论 -
聊聊Linux中线程和进程的联系与区别!
前面我们看到,进程和线程创建都是调用内核中的 do_fork 函数来执行的。和 copy_files 函数类似,在 copy_fs 中如果指定了 CLONE_FS(创建线程的时候),并没有真正申请独立的 fs_struct 出来,近几年只是在原有的 fs 里的 users +1 就算是完事。从代码看出,如果指定了 CLONE_FILES(创建线程的时候),只是在原有的 files_struct 里面 +1 就算是完事了,指针不变,仍然是复用创建它的进程的 files_struct 对象。转载 2022-12-19 22:10:26 · 362 阅读 · 0 评论 -
Linux进程是如何创建出来的?
在这篇文章中,我用 Nginx 创建 worker 进程的例子作为引入,然后带大家了解一些进程的数据结构 task_struct,最后又带大家看一下 fork 执行的过程。在 fork 创建进程的时候,地址空间 mm_struct、挂载点 fs_struct、打开文件列表 files_struct 都要是独立拥有的,所以都去申请内存并初始化了它们。但由于今天我们的例子父子进程是同一个命名空间,所以 nsproxy 还仍然是共用的。转载 2022-12-19 22:00:12 · 498 阅读 · 0 评论 -
Linux 0.11-信号-48
我们发现,这次按下第二次 CTRL+C 程序就会退出了,这也间接证明了,当没有为 SIGINT 注册信号处理函数时,程序接收到 CTRL+C 的 SIGINT 信号时便会退出。我们继续往下进行,如果在你的程序正在被 shell 程序执行时,你按下了键盘中的 CTRL+C,你的程序就被迫终止,并再次返回到了 shell 等待用户输入命令的状态。通过这种类似 “倒叙” 的讲述方法,希望你能明白,其实技术的本质并不复杂,只不过被抽象之后,由于你不了解下面的细节,就变得云里雾里了。转载 2022-11-12 21:43:12 · 243 阅读 · 0 评论 -
Linux 0.11-读取硬盘数据的细节-47
当设备的当前请求项为空时,也就是没有在执行的块设备请求项时,ll_rw_block 就会在执行到 add_request 方法时,直接执行 do_hd_request 方法发起读盘请求。随后,将当前设备的当前请求项 CURRENT,即 request 数组里的一个请求项 request 的 dev 置空,并将当前请求项指向链表中的下一个请求项。这个方法主要是调用 do_hd 方法,这个方法是一个指针,就是高级语言里所谓的接口,读操作的时候,将会指向 read_intr 这个具体实现。转载 2022-11-12 21:33:15 · 456 阅读 · 0 评论 -
Linux 0.11-读硬盘数据全流程-46
接下来,file_read 方法做了读盘的全部操作,通过 bmap 获取到了硬盘全局维度的数据块号,然后 bread 将数据块数据复制到缓冲区,然后 put_fs_byte 再将缓冲区数据复制到用户内存。那么开始的两行计算代码。具体说来,就是如上图所示,每个进程的线性地址范围,是。方法,一个字节一个字节地,将缓冲区里的数据,复制到用户指定的内存 buf 中去了,当然,只会复制 count 字节。也就是说,假如我想要读这个文件的第一个块号的数据,该函数返回的事你这个文件的第一个块在整个硬盘中的哪个块中。转载 2022-11-12 21:04:50 · 1074 阅读 · 0 评论 -
Linux 0.11-解析并执行 shell 命令-45
我们已经讲过如何通过 execve 加载并执行 shell 程序了,并且在加载 shell 程序时,并不会立即将磁盘中的数据加载到内存,而是会在真正执行 shell 程序时,引发缺页中断,从而按需将磁盘中的数据加载到内存。那我们看看,它是如何实现的,我们走到 runcmd 方法中的 PIPE 这个分支里,也就是当解析出输入的命令是一个管道命令时,所应该做的处理。你再读读这段话,最终的效果就是,将 1 号文件描述符,也就是标准输出,指向了 p[1] 管道的写口,也就是 p[1] 原来所指向的地方。转载 2022-11-12 20:41:55 · 353 阅读 · 0 评论 -
Linux 0.11-进程的阻塞与唤醒-44
OK,现在我们的 shell 进程,通过 read 函数,中间经过了层层封装,以及后面经过了阻塞与唤醒这一番折腾后,终于把键盘输入的字符们,成功由 tty 中的 secondary 队列,读取并存放与 buf 指向的内存地址处。而上一个进程唤醒后,和这个被唤醒的进程一样,也会走过它自己的 sleep_on 函数的后半段,把它的上一个进程,也就是上上一个进程唤醒。也就是说,通过每一个当前任务所在的代码块中的 tmp 变量,总能找到上一个正在同样等待一个资源的进程,因此也就形成了一个链表。转载 2022-11-12 20:18:37 · 581 阅读 · 0 评论 -
Linux 0.11-shell 程序读取你的命令-43
read 的第一个参数是 0,也就是 0 号文件描述符,之前我们在讲第四部分的时候说过,shell 进程是由进程 1 通过 fork 创建出来的,而进程 1 在 init 的时候打开了。其中 GETCH 就是个宏,改变 secondary 队列的队头队尾指针,你自己写个队列数据结构,也是这样的操作,不再展开讲解。当我们再次按下键盘,使得 secondary 队列中有字符时,也就打破了为空的条件,此时就应该将之前的进程唤醒了,这在上一回。第一,我们键盘输入的字符,此时已经到达了控制台终端 tty 结构中的。转载 2022-11-12 19:14:29 · 342 阅读 · 0 评论 -
Linux 0.11-用键盘输入一条命令-42
新建一个非常简单的 info.txt 文件。在命令行输入一条十分简单的命令。这条命令的意思是读取刚刚的 info.txt 文件,输出它的行数。我们先从最初始的状态开始说起。最初始的状态,电脑屏幕前只有这么一段话。然后,我们按下按键 ‘c’,将会变成这样。我们再按下 ‘a’接下来,我们再依次按下 ‘t’、空格、‘i’ 等等,才变成了这样。我们今天就要解释这个看起来十分"正常"的过程。凭什么我们按下键盘后,屏幕上就会出现如此的变化呢?老天爷规定的么?我们就从按下键盘上的 ‘c’ 键开始说起。转载 2022-11-11 22:18:45 · 368 阅读 · 0 评论 -
Linux 0.11-shell命令的执行预热篇-41
当你通过前四部分理解了操作系统启动流程,再继续通过第五部分理解了一条命令的执行流程,那么你对操作系统的原理就真的不再畏惧了,因为操作系统一共就这两件事,一个是把自己启动起来,另一个是不断接收用户的命令并且执行它,就这么简单。有些部分的讲解就没有那么详细了,因为不影响启动流程的理解,比如说从硬盘中读取数据到内存,其实中间涉及到文件系统,以及文件系统这个抽象层下方的块设备驱动程序,这部分非常复杂,不但分层和抽象层次较多,且涉及到阻塞与唤醒等操作。好的,那就让我们看看,这条命令的执行,到底经历了些什么吧!转载 2022-11-11 22:05:26 · 213 阅读 · 0 评论 -
Linux 0.11-操作系统启动完结篇-40
到此为止,操作系统终于启动完毕,达到了怠速的状态,它本身设置好了一堆中断处理程序,随时等待着中断的到来进行处理,同时它运行了一个 shell 程序用来接受我们普通用户的命令,以同人类友好的方式进行交互。利用刚刚建立好的文件系统,以及进程 1 的与外设交互的能力,创建出了进程 2,此时进程 2 与进程 1 一样也具有与外设交互的能力,这为后面 shell 程序的创建打好了基础。整个操作系统终于通过四个部分的讲解,完成了它的启动,达到了一个怠速状态,留下了一个 shell 程序等待用户指令的输入并执行。转载 2022-11-10 19:21:02 · 389 阅读 · 0 评论 -
Linux 0.11-操作系统启动完毕-39
我们先是建立了操作系统的一些最基本的环境与管理结构,然后由进程 0 fork 出处于用户态执行的进程 1,进程 1 加载了文件系统并打开终端文件,紧接着就 fork 出了进程 2,进程 2 通过我们刚刚讲述的 execve 函数将自己替换成了 shell 程序。到此为止,操作系统终于启动完毕,达到了怠速的状态,它本身设置好了一堆中断处理程序,随时等待着中断的到来进行处理,同时它运行了一个 shell 程序用来接受我们普通用户的命令,以同人类友好的方式进行交互。接口供上层的应用程序调用,仅此而已。转载 2022-11-10 19:11:26 · 247 阅读 · 0 评论 -
Linux 0.11-shell 程序跑起来了-38
由此你是不是也感受到了 xv6 源码的简单之美,真的是见名知意,当你跟我走完这个 Linux 0.11 之旅后,再去阅读 xv6 的源码你会觉得非常舒服,因为 Linux 0.11 很多地方都用了非常骚的编码技巧,使得理解起来很困难,谁让 Linus 这么特立独行呢。好了,接下来我们就阅读一下 shell 程序的源码,只需要找到它的一个具体实现即可。其实我就想说,shell 程序也仅仅是个程序而已,它的输出,它的输入,它的执行逻辑,是完全可以通过阅读程序源码来知道的,和一个普通的程序并没有任何区别。转载 2022-11-10 18:48:33 · 346 阅读 · 0 评论 -
Linux 0.11-缺页中断-37
所以顺利地映射到了物理地址,也就是 /bin/sh 的代码部分(从硬盘加载过来的),那接下来就终于可以执行 /bin/sh 程序,也就是 shell 程序了。可是,128M 这个线性地址并没有页表映射它,也就是因为上面我们说的,我们除了 /bin/sh 文件的头部加载到了内存外,其他部分并没有进行加载操作。但有个问题是,我们仅仅将 /bin/sh 文件的头部加载到了内存,其他部分并没有进行加载,那我们是怎么执行到的 /bin/sh 的程序指令呢?那这个 shell 程序到底是啥呢?转载 2022-11-10 15:12:12 · 607 阅读 · 0 评论 -
Linux 0.11-调试 Linux 最早期的代码-36
我用的方式是,在 windows 上,搞一个 Ubuntu 16.04 的虚拟机,在里面用 qemu 启动一个开启了调试的 Linux 0.11 系统,然后用本机的 vscode remote ssh 连接到虚拟机,并开启 gdb 调试,最终的效果如下。要想成功调试 Linux 0.11,需要进行很多改造,并依赖一些古老的工具链,对于仅仅是将 Linux 0.11 作为研究操作系统的手段的我们,无需花费精力自己去改造它,踩各种坑。这一步直接下官网上的是不行的,因为那个依赖好多古老的工具链。转载 2022-11-10 14:07:47 · 1742 阅读 · 0 评论 -
Linux 0.11-execve函数-35
至于 /bin/sh 文件是怎么构造出来的,那就是 gcc 编译和链接那些事了,而且 Linux 0.11 所用的可执行文件格式 a.out,已经被现在的 ELF 格式所取代,那就更不在我们要研究的范畴,本系列还是要划分好边界问题的,不然就无休止了。最后,将 sp 返回给 p,这个 p 将作为一个新的栈顶指针,给即将要完成替换的 /bin/sh 程序,也就是下面的代码。格式文件的头部结构,现在的 Linux 已经弃用了这种古老的格式,改用 ELF 格式了,但大体的思想是一致的。转载 2022-11-10 12:12:57 · 677 阅读 · 1 评论 -
Linux 0.11-进程2的创建-34
书接上回,上回书咱们说到,进程 1 通过 open 函数建立了与外设交互的能力,具体其实就是打开了 tty0 这个设备文件,并绑定了标准输入 0,标准输出 1 和 标准错误输出 2 这三个文件描述符。此时,进程 2 与进程 1 几乎完全一样,只不过进程 2 通过 close 和 open 操作,将原来进程 1 的指向标准输入的 0 号文件描述符,重新指向了 /etc/rc 文件。到目前为止,进程 2 与进程 1 的区别,仅仅是将 0 号文件描述符重新指向了 /etc/rc 文件,其他的没啥区别。转载 2022-11-10 11:30:29 · 188 阅读 · 0 评论 -
Linux 0.11-打开终端设备文件-33
其实就是初始化这个 f,包括刚刚找到的 inode 值。最后返回给上层文件描述符 fd 的值,也就是零。转载 2022-11-10 11:14:21 · 524 阅读 · 1 评论 -
Linux 0.11-加载根文件系统-32
注意到 file 结构里有个 f_inode 字段,通过 f_inode 即可找到它的 inode 信息,inode 信息包含了一个文件所需要的全部信息,包括文件的大小、文件的类型、文件所在的硬盘块号,这个所在硬盘块号,就是文件的位置咯。从整体上说,它就是要把硬盘中的数据,以文件系统的格式进行解读,加载到内存中设计好的数据结构,这样操作系统就可以通过内存中的数据,以文件系统的方式访问硬盘中的一个个文件了。好了,文件系统格式的说明,我们就简单说明完毕了,MINIX 文件系统已经过时,你可以阅读我之前写的。转载 2022-11-10 10:48:32 · 502 阅读 · 0 评论 -
Linux 0.11-拿到硬盘信息-31
所以第一,需要硬盘本身就有文件系统的信息,硬盘不能是裸盘,这个不归操作系统管,你为了启动我的 Linux 0.11,必须拿来一块做好了文件系统的硬盘来。,讲述了进程 0 调用了 fork 函数创建了一个新的进程 —— 进程 1,并且使其达到了可以被调度的状态,fork 就算正式完成了自己的使命。关于系统调用的原理,在。第二,需要读取硬盘的数据到内存,那就必须需要知道硬盘的参数信息,这就是我们本讲所做的事情的意义。函数的内部实现,那是相当复杂的,涉及到与缓冲区配合的部分,还有读写请求队列的设置,以及中断。转载 2022-11-10 10:36:06 · 254 阅读 · 0 评论 -
Linux 0.11-写时复制-30
写时复制的原理网上讲述的文章很多,今天来一篇很直接的文章,通过看看 Linux 0.11 这个最简单的操作系统,从源码层面把写时复制的原理搞清楚。Linux 0.11 的缺页中断处理函数的开头是用汇编写的,看着太闹心了,这里我选 Linux 1.0 的代码给大家看,逻辑是一样的。如果你前面没读懂,你只需要知道,页表当中有一位是表示读\写的,而 Linux 0.11 初始化时,把它设置为了 1,表示可读写。,表示读写权限,0 表示只读,那么此时往这个页表示的内存范围内写数据,则不允许。转载 2022-11-09 21:10:28 · 245 阅读 · 0 评论 -
Linux 0.11-一个新进程的诞生完结篇-29
这一部分的 fork 函数只用于进程 0 创造进程 1 的过程,而之后的新进程创建,比如进程 1 里 fork 创建进程 2,也都是这样的套路。switch_to 这个终极函数,会保存当前进程上下文,恢复要跳转到的这个进程的上下文,同时使得 CPU 跳转到这个进程的偏移地址处。开始复制进程信息的时候,由于进程 1 的结构还没弄好,此时如果进程调度到了进程 1,那就坏事了。而所有复制工作完成后,进程 1 就拥有了运行的内容,进程基本信息也有了,进程的内存规划也完成了。那就是 init 这个函数的故事了。转载 2022-11-09 20:42:26 · 280 阅读 · 0 评论 -
Linux 0.11-透过 fork 来看进程的内存规划-28
欲知后事如何,且听下回分解。转载 2022-11-09 20:17:54 · 320 阅读 · 0 评论 -
Linux 0.11-fork 中进程基本信息的复制-27
又是个 for 循环,刚刚已经找到一个可用的 pid 号了,那这一步就是再次遍历这个 task[] 试图找到一个空闲项,找到了就返回素组索引下标。,判断 ++last_pid 是不是小于零了,小于零说明已经超过 long 的最大值了,重新赋值为 1,起到一个保护作用,这没什么好说的。然后,进程 1 和进程 0 目前是完全复制的关系,但有一些值是需要个性化处理的,下面的代码就是把这些不一样的值覆盖掉。那妥了,这个方法的意思非常简单,因为存储进程的数据结构是一个 task[64] 数组,这个是在之前。转载 2022-11-09 19:55:15 · 303 阅读 · 0 评论 -
Linux 0.11-通过 fork 看一次系统调用-26
书接上回,上回书咱们说到,我们通过自己设计了一遍进程调度,又看了一次 Linux 0.11 的进程调度的全过程。有了这两回做铺垫,我们下一回就该非常自信地回到我们的主流程!也就是这个 fork 函数干了啥?这个 fork 函数稍稍绕了点,我们看如下代码。别急,我把它变成稍稍能看得懂的样子,就是这样。所以,把宏定义都展开,其实就相当于定义了一个函数。仅此而已。具体看一下 fork 函数里面的代码,又是讨厌的内联汇编,不过上面我已经变成好看一点的样子了,而且不用你看懂,听我说就行。关键指令就是一个 0转载 2022-11-09 19:42:55 · 384 阅读 · 0 评论 -
Linux 0.11-从一次定时器滴答来看进程调度-25
CPU 规定,如果 ljmp 指令后面跟的是一个 tss 段,那么,会由硬件将当前各个寄存器的值保存在当前进程的 tss 中,并将新进程的 tss 信息加载到各个寄存器。这样,当时钟中断,也就是 0x20 号中断来临时,CPU 会查找中断向量表中 0x20 处的函数地址,即中断处理函数,并跳转过去执行。switch_to 这个终极函数,会保存当前进程上下文,恢复要跳转到的这个进程的上下文,同时使得 CPU 跳转到这个进程的偏移地址处。接着,这个进程就舒舒服服地运行了起来,等待着下一次时钟中断的来临。转载 2022-11-09 11:32:05 · 359 阅读 · 0 评论 -
Linux 0.11-如果让你来设计进程调度-24
我们知道了进程调度的开始,要从一次定时器滴答来触发,通过时钟中断处理函数走到进程调度函数,然后去进程的结构 task_struct 中取出所需的数据,进行策略计算,并挑选出下一个可以得到 CPU 运行的进程,跳转过去。就是,由一个不受任何程序控制的,第三方的不可抗力,每隔一段时间就中断一下 CPU 的运行,然后跳转到一个特殊的程序那里,这个程序通过某种方式获取到 CPU 下一个要运行的程序的地址,然后跳转过去。那么下一讲,我们从一次时钟中断出发,看看一次 Linux 0.11 的进程调度的全过程。转载 2022-11-09 11:21:03 · 327 阅读 · 1 评论 -
Linux 0.11-从内核态到用户态-23
所以其实,最终效果上看就是按顺序执行了我们所写的指令,仿佛没有经过什么中断和中断返回的过程,但却通过中断返回实现了特权级的翻转,也就是从内核态变为了用户态,顺便设置了栈段、代码段和数据段的基地址。转载 2022-11-09 11:11:40 · 826 阅读 · 0 评论 -
Linux 0.11-一个新进程的诞生-22
一旦转变为了用户态,那么之后的代码将一直处于用户态的模式,除非发生了中断,比如用户发出了系统调用的中断指令,那么此时将会从用户态陷入内核态,不过当中断处理程序执行完之后,又会通过中断返回指令从内核态回到用户态。当然,当你知道了新进程诞生的过程之后,进程 2 的创建,就和进程 1 的创建一样了,在后面的章节中你将不会再困惑创建新进程的过程,减轻了学习负担。如果你觉得这些话很困惑,就对了,在理解了整个这一块的细节之后,尤其是对于进程调度这种被人赋予了好多虚头巴脑的名词的地方,你会豁然开朗的。转载 2022-11-08 10:14:37 · 216 阅读 · 0 评论 -
Linux 0.11-初始化部分总结-21
这张图展示了整个系列的结构那我们今天就来给第二部分做个梳理。第二部分所讲的代码,就和第二部分的目录一样规整,一个 init 方法对应一个章节,简单粗暴。sti();if(!} for(;;) pause();}如果坚持到这里了,先给自己鼓鼓掌!这个过程,你可能觉得无聊,因为全是各种数据结构、中断、外设的初始化工作,后面将会怎么用它们,并没有展开讲解。转载 2022-11-08 10:13:44 · 303 阅读 · 0 评论 -
Linux 0.11-硬盘初始化-20
还记得小时候我特别喜欢收集软盘,里面分门别类存上我做的 Flash 动画,然后在软盘上的那个纸标签上写上文字,表示软盘存了什么,想想看还是回忆呢。函数,即便是经过系统调用、文件系统、缓冲区管理等等过程,但只要是读写硬盘,最终都要调用到这个最底层的函数,殊途同归,逃不掉的!里还有很多读写硬盘的方法,这个在之后文件系统用到他们时,自然会讲起,这里就抛个引子,看看读硬盘最最底层的操作流程,是怎样的。坚持读到现在的,都为自己鼓鼓掌!OK,本章就结束了,仅仅看初始化的工作,太简单了,连图都不用画就结束了。转载 2022-11-07 21:16:40 · 551 阅读 · 0 评论 -
Linux 0.11-内存缓冲区的管理-19
可是内核程序占多大内存在写的时候完全不知道,就算知道了如果改动一点代码也会变化,所以就由程序编译链接时由链接器程序帮我们把这个内核代码末端的地址计算出来,作为一个外部变量 end 我们拿来即用,就方便多了。而且幸运的是,floppy_init 是软盘初始化,现在软盘几乎都被淘汰了,计算机中也没有软盘驱动器了,所以这个我们完全可以不看,那就剩下一个。也就是说,读取块设备的数据(硬盘中的数据),需要先读到缓冲区中,如果缓冲区已有了,就不用从块设备读取了,直接取走。你看,之前的疑惑解决了吧?转载 2022-11-07 21:04:29 · 318 阅读 · 0 评论 -
Linux 0.11-进程模块初始化-18
我们初始化了一个结构为 task_struct 的数组,未来这里会存放所有进程的信息,并且我们给数组的第一个位置附上了 init_task.init 这个具体值,也是作为未来进程 0 的信息。找到些感觉没,有没有越来越发现,操作系统有点靠中断驱动的意思,各个模块不断初始化各种中断处理函数,并且开启指定的外设开关,让操作系统自己慢慢“活”了起来,逐渐通过中断忙碌于各种事情中,无法自拔。当然,对于理解操作系统,流程和数据结构最为重要了,而这一段作为整个流程的起点,以及建立数据结构的地方,就显得格外重要了。转载 2022-11-07 20:42:32 · 308 阅读 · 0 评论 -
Linux 0.11-操作系统如何获取时间-17
操作系统最大的魅力,就在于它借力完成了一项伟大的事,借 CPU 的力,借硬盘的力,借内存的力,以及现在借 CMOS 的力。作为用户也可以通过敲击键盘,或调用诸如 printf 这样的库函数,在屏幕上输出信息,同时支持换行和滚屏等友好设计,这些都是 tty_init 初始化,以及其对外封装的小功能函数,来实现的。至于这个外设内部是怎么实现的,对使用它的操作系统而言,是个黑盒,无需关心。设备去读,解放 CPU,但和硬盘的交互,通通都是按照硬件手册上的端口说明,来操作的,实际上也是做了一层封装。转载 2022-11-07 20:24:47 · 282 阅读 · 0 评论 -
Linux 0.11-按下键盘后为什么屏幕上就会有输出-16
就讲完了,要知道这个文件可是整个内核中代码量最大的文件,可是功能特别单一,也都很简单,主要是处理键盘各种不同的按键,需要写好多 switch case 等语句,十分麻烦,我们这里就完全没必要去展开了,就是个苦力活。的效果,无非就是当检测到光标已经出现在最后一行最后一列了,那就把每一行的字符,都复制到它上一行,其实就是算好哪些内存地址上的值,拷贝到哪些内存地址,就好了。这个方法是串口中断的开启,以及设置对应的中断处理程序,串口在我们现在的 PC 机上已经很少用到了,所以这个直接忽略,要讲我也不懂。转载 2022-11-07 20:04:01 · 303 阅读 · 0 评论 -
Linux 0.11-读取硬盘前的准备工作有哪些-15
具体读盘操作,后面会有详细的章节展开讲解,本讲你只需要知道,我们在 main 函数的 init 系列函数中,通过 blk_dev_init 为后面的块设备访问,提前建立了一个数据结构,作为访问块设备和内存缓冲区之间的桥梁,就可以了。具体说来,就是该函数会往刚刚的设备的请求项链表 request[32] 中添加一个请求项,只要 request[32] 中有未处理的请求项存在,都会陆续地被处理,直到设备的请求项链表是空为止。哎哟,这就有点头大了,刚刚的函数虽然很短,但看到这个结构体我们知道了,重点在这呢。转载 2022-11-07 19:52:55 · 296 阅读 · 0 评论 -
Linux 0.11-你的键盘是什么时候生效的?-14
这个 trap 与 system 的区别仅仅在于,设置的中断描述符的特权级不同,前者是 0(内核态),后者是 3(用户态),这块展开将会是非常严谨的、绕口的、复杂的特权级相关的知识,不明白的话先不用管,就理解为都是设置一个中断号和中断处理程序的对应关系就好了。当然首先你得知道,按下键盘后会触发中断,CPU 收到你的键盘中断后,根据中断号,寻找由操作系统写好的键盘中断处理程序。好啦,今天的文章就到这里了,中断的原理和细节,就看我之前的文章,看到这个方法的全部代码后,你可能会会心一笑,也可能一脸懵逼。转载 2022-11-07 19:18:02 · 258 阅读 · 0 评论 -
Linux 0.11 - 操作系统用一张大表管理内存-13
1M 以下的内存这个数组干脆没有记录,这里的内存是无需管理的,或者换个说法是无权管理的,也就是没有权利申请和释放,因为这个区域是内核代码所在的地方,不能被“污染”。,2M 是缓冲区的末端,缓冲区的开始在哪里之后再说,这些地方不是主内存区域,因此直接标记为 USED,产生的效果就是无法再被分配了。我们本讲不展开,不过我们简单展望一下,看看申请内存的过程中,是如何使用 mem_map 这个结构的。今天我们不聊具体内存管理的算法,我们就来看看,操作系统用什么样的一张表,达到了管理内存的效果。转载 2022-11-07 11:33:31 · 287 阅读 · 0 评论