Linux0.11内核之体系结构(二)

Linux内核体系结构

前言

说明一下为什么要学习Linux0.11内核

  • Linux0.11是保存下来最早的Linux版本
  • 代码量最少,功能相对齐全,后来的版本都是在此基础上加的。
  • 学习Linux0.11能够更快的掌握内核知识。

学习技巧:一些关键的点是要细心去看的,想要学懂就要静下心来。
大家一起加油!!!

Linux0.11内核系列前期回顾
Linux0.11内核之体系结构(一)

我将继续 Linux内核对内存的管理和使用 的学习

Linux内核对内存的管理和使用

4.内存分页管理

内存分页管理机制的基本原理是将CPU整个线性内存区划分为4096字节为1页的内存页面。程序申请使用内存时,系统就以内存页面为单位进行分配的。内存分页机制的实现方式与分段机制很相似,分页机制是在分段机制之上实现的,对系统内存具有非常灵活的控制权,并且在分段机制的内存保护上更增加了分页保护机制。

分页机制线性地址到物理地址的变换过程
在这里插入图片描述
寄存器CR3保存着当前目录页表在物理内存中的基地址(基地址就是当前页表的起始地址),32位的线性地址杯分为三个部分:页目录表、页表项和页内偏移值。

1个页表可有1024项,一项占4个kb,因此一个页表最多可以映射1024x4KB=4MB内存;一个页目录表最多有1024项,对应1024个二级页表,一个页目录表最多可以映射1024x4MB=4GB 容量的内存。即一个页目录表就可以映射整个线性地址空间范围,32位的内存空间为4G。

Linux 0.11系统中内核和所有任务都共用同一个页目录表,使得任何时刻处理器线性地址空间到物理地址空间的映射函数都一样。因此为了让内核和所有任务都不互相重叠和干扰,它们都必须从虚拟地址空间映射到线性地址空间的不同位置,即占用不同的线性地址空间范围。

5.CPU 多任务和保护方式

Interl 80X86 CPU 共分为4个保护级,0级是最高优先级,3级是最低级。
Linux0.11 操作系统使用了CPU的 0 和 3 两个保护等级。内核代码本身会由系统中的所有任务共享。而每个任务则都有自己的代码和数据区,这两个区域保存于局部地址空间,因此系统中的其他任务是看不见的(不能访问的)。而内核代码和数据是由所有任务共享的,因此它保存在全局地址空间中。
在这里插入图片描述

图中同心圆代表CPU的保护级别(保护层),这里仅使用了CPU的0级和3级。而径向射线则用来区分系统中的各个任务。每条径向射线指出了各任务的边界。除了每个任务虚拟地址空间的全局地址区域,任务1中的地址与任务2中相同地址处是无关的。

当一个任务(进程)执行系统调用进入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。

6.虚拟地址、线性地址和物理地址之间的关系

前面我们根据内存分段和分页机制详细说明了CPU的内存管理方式。现在我们以Linux 0.11系统为例,详细说明内核代码和数据以及各任务的代码和数据在虚拟地址空间、线性地址空间和物理地址空间中的对应关系。

内核代码和数据的地址

对于Linux 0.11内核代码和数据来说,在head.s程序的初始化操作中已经把内核代码段和数据段都设置成为长度为 16MB 的段。在线性地址空间中这两个段的范围重叠,都是从线性地址 0 开始到地址 0xFFFFFF 共 16MB 地址范围。在该范围中含有内核所有的代码、内核段表(GDT、IDT、TSS)、页目录表和内核的二级页表、内核局部数据以及内核临时堆栈。其页目录表和二级页表已设置成把 0-16MB 的线性地址空间一一对应到物理地址上,占用了4个目录项,即4个二级页表。因此对于内核代码或数据的地址来说,我们可以直接把它们看作是物理内存中的地址。
内核的虚拟地址空间、线性地址空间和物理地址空间三者之间的关系
在这里插入图片描述

  • 内核代码段和数据段区域在线性地址空间和物理地址空间中是一样的
  • GDT(全局描述符表) 和 IDT(中断描述符表) 在内核数据段中,因此它们的线性地址也同样等于它们的物理地址
  • 所有其他任务所需要的物理内存页面与线性地址中的不同或部分不同,内核需要动态地在主内存区中为它们作映射操作,动态地建立页目录项和页表项
任务 0 的地址对应关系(学习了解)

在这里插入图片描述
在这里插入图片描述

任务0是系统中一个人工启动的第一个任务。它的代码段和数据段长度被设置为640KB。该任务的代码和数据直接包含在内核代码和数据中,是从线性地址0开始的640KB内容,因此可以它直接使用内核代码已经设置好的页目录和页表进行分页地址变换。同样,它的代码和数据段在线性地址空间中也是重叠的。
三个地址空间中的映射关系

任务0直接被包含在内核代码中,因此不需要为其再另外分配内存页。它运行时所需要的内核态堆栈和用户态堆栈空间也都在内核代码区中,并且由于在内核初始化时(head.s)这些内核页面在页表项中的属性都已经被设置成了可读可写,因此用户堆栈虽然在内核空间中,但任务0仍然能对其进行读写操作。

任务 1 的地址对应关系(学习了解)

与任务0类似,任务1也是一个特殊的任务。它的代码也在内核代码区域中。与任务0不同的是在线性地址空间中,系统在使用fork()创建任务1 (init进程)时为存放任务1的二级页表而在主内存区申请了一页内存来存放,并复制了父进程(任务0)的页目录和二级页表项。因此任务1有自己的页目录和页表表项,它把任务1占用的线性空间范围64MB–128MB(实际上是64MB–64MB+640KB)也同样映射到了物理地址0–640KB处。此时任务1的长度也是640KB,并且其代码段和数据段相重叠,只占用一个页目录项和一个二级页表。另外,系统还会为任务1在主内存区域中申请一页内存用来存放它的任务数据结构和用作任务1的内核堆栈空间。
任务1数据结构信息中包括任务1的TSS 段结构信息:
在这里插入图片描述

7.用户申请内存的动态分配
  • 当用户应用程序使用C函数库中的内存分配函数malloc()申请内存时,这些动态申请的内存容量或大小均由高层次的C库函数malloc()来进行管理,内核本身并不会插手管理。
  • 内核会为进程使用的代码和数据空间维护一个当前位置值 brk,这个值保存在每个进程的数据结构中。它指出了进程代码和数据(包括动态分配的数据空间)在进程地址空间中的末端位置。
  • 当malloc()函数为程序分配内存时,它会通过系统调用brk()把程序要求新增的空间长度通知内核,内核代码从而可以根据 malloc()所提供的信息来更新brk 的值,但并此时并不为新申请的空间映射物理内存页面。
  • 只有当程序寻址到某个不存在对应物理页面的地址时,内核才会进行相关物理内存页面的映射操作。

若进程代码寻址的某个数据所在的页面不存在,并且该页面所处位置属于进程堆范围,即不属于其执行文件映像文件对应的内存范围中,那么CPU就会产生一个缺页异常,并在异常处理程序中为指定的页面分配并映射一页物理内存页面。
至于用户程序此次申请内存的字节长度数量和在对应物理页面中的具体位置,则均由C库中内存分配函数 malloc()负责管理。内核以页面为单位分配和映射物理内存,该函数则具体记录用户程序使用了一页内存的多少字节。剩余的容量将保留给程序再申请内存时使用。

当用户使用内存释放函数free()动态释放已申请的内存块时,C库中的内存管理函数就会把所释放的内存块标记为空闲,以备程序再次申请内存时使用。在这个过程中内核为该进程所分配的这个物理页面并不会被释放掉。只有当进程最终结束时内核才会全面收回已分配和映射到该进程地址空间范围的所有物理内存页面。

总结

本来我是想记录的精炼一点,但是我又觉得如果写少了,可能会看的没那么明白。事实上我还是删减了许多,但是字还是好多啊!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值