寻呼到底是什么?OSDEV [英] What is paging exactly? OSDEV

查看:0
本文介绍了寻呼到底是什么?OSDEV的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写自己的操作系统,到了需要设置分页的时候。我编写了一些代码,这些代码似乎可以工作,但我意识到我不理解分页是如何工作的。现在我会试着解释我是如何理解事情的,我会有几个问题!

据我所知,分页是一种将地址映射到其他地址的方式,以便每个应用程序都可以看到完整的地址空间(?)。有一种叫做页目录的东西,它存储了1024个4字节的条目,每个条目都包含指向页表的指针,页表也有1024个条目。页表的每个条目都有一个指针,该指针指向4KiB的物理地址块的开始。这意味着4096字节*页表中的1024个条目*页目录中的1024个条目=可映射的4GiB的RAM。例如,我可以将应用程序加载到0x80000000,并将该地址映射到0x00000000,应用程序将看到其地址从0x00000000开始。

问题:

  1. 是每个应用程序都有自己的页面目录,还是只有一个页面目录,应用程序如何访问这些页面,它们具体做些什么?
  2. 如果为应用程序分配4 KiB空间块或一页,应用程序如何查看全部地址空间?
  3. 如何将页面写入硬盘?
  4. 我们应该如何为应用程序分配要使用的页面?

推荐答案

您说得对,应用程序看到的地址空间已满。通常,应用程序称为进程。每个进程都会看到一个完整的虚拟地址空间,但这是因为它的页表已设置,因此它将能够访问整个虚拟地址空间,而不会干扰其他进程(其地址访问将转换到与其他进程不同的位置)。

是每个应用程序都有自己的页面目录,还是只有一个页面目录,应用程序如何访问这些页面,它们具体做些什么?

每个进程/app都有自己的页面目录。在x86 32位系统上,虚拟地址将由MMU从CR3寄存器开始转换。因此,您用页面目录的底部加载CR3寄存器,而MMU自己完成其余的工作。处理器的每个核心一次只运行一个进程。对于当前进程,每个内核都有自己的CR3寄存器。当发生上下文切换(由于计时器中断)时,操作系统会将CR3寄存器更改为指向正在发生的新进程的页面目录的底部。

例如,Linux通过在每个进程的任务结构的mm结构中保存一个指向页面目录的指针来实现这一点。Mm结构是进程的内存映射。TASK_STRUCT是一个过程描述符(有时称为过程控制块或PCB)。当发生上下文切换时,Linux使用mm结构中的pgd指针指向的地址加载CR3寄存器。

进程并不真正访问页面。进程只执行代码,其代码(仅包含虚拟地址)由MMU自动转换为物理地址。为了在x86 32位系统上转换虚拟地址,MMU获取虚拟地址并将其分割为3个部分。例如,虚拟地址0x12345678将具有以下拆分(所有地址的拆分方式相同):

             Offset in pd     Offset in pt     Offset in physical page      
0x12345678 = 0001 0010 00     1101 0001 01     0110 0111 1000
10个最高有效位表示页面目录中的偏移量。中间的10位是页表中的偏移量,右边的最后12位是物理页中的偏移量。上述示例地址引用PD中的偏移量0x48、PT中的偏移量0x345和物理页中的偏移量0x678。因此,MMU将使用CR3寄存器来查找PD的底部。然后,它将使用PD中的条目0x48来查找页表的地址。一旦它找到页表的地址,它将使用条目0x345来查找物理页的地址。然后它将访问物理页面中地址0x678。

如果为应用程序分配4 KiB空间块或一页,应用程序如何查看全部地址空间?

编译用C/C++编写的程序时,大多数部分都是静态编译的。程序的大多数部分将位于可执行文件中。如今,可执行文件支持虚拟寻址。大多数情况下,将加载程序部分的虚拟地址存储在可执行文件中。当您启动该可执行文件时,操作系统将从硬盘加载该可执行文件,然后为新进程设置页表。它将映射虚拟地址,以便将进程的内存访问映射到其自己的代码。

例如,可执行文件可以告诉Linux将其第一段(代码的第一部分)映射到0x400000。然后,Linux将在RAM中的任何位置为该进程分配内存。然后,Linux将为该进程创建页表。当CPU获取该进程的指令时,页表将告诉MMU去哪里。当调度器为该进程分配一个CPU来运行时,Linux将跳到该进程的第一条指令(在0x400000处)。当CPU获取0x400000处的指令时,MMU使用页表将该地址转换为RAM(Linux决定实际放置该进程的位置)中的任何位置。

您说得对,进程一开始不能访问整个虚拟地址空间。他们可以在代码中引用它,但大多数情况下,它会跳到任何地方并触发页面错误。Linux可能会终止该进程。实际上,该进程可以访问整个虚拟地址空间,因为可以将页面交换到硬盘。如果一个进程分配了4 GB的RAM(并且有其他进程在运行),该进程将不会看到RAM已满,并且操作系统实际上正在将页面交换到硬盘,以使该进程与系统的其余部分一起工作。这就是为什么进程可以虚拟访问整个虚拟地址空间(其大小与物理内存相同)的原因。

如何将页面写入硬盘?

在一个只是为了好玩而编写的业余爱好操作系统中,大多数情况下你不需要这样做。当内存已满的情况下,有时这是必要的。因此,Linux在RAM中获取页面,并将它们加载到硬盘中,跟踪它们的位置。当进程访问RAM中不存在的页面时(因为它的当前位未在页表中设置),CPU会触发页面错误。页面错误处理程序(在引导时由操作系统注册)可以访问所有内核结构。因此,它将在硬盘上找到被逐出的页面,并将该页面交换回RAM(同时驱逐另一页面)。

我不是完全了解,因为我从未编写过真正的现代硬盘驱动程序。以32位模式在硬盘上存储内容的最简单方法是使用PIO模式,该模式与LBA一起工作。你可以在osdev.org上阅读更多关于ATA磁盘的PIO模式的文章。

在大多数现代硬件中,我认为它主要是通过与PCI一起工作的DMA控制器来完成的。您可以通过读取一些寄存器来枚举PCI设备。您可以通过查看MCFG ACPI表找到PCI配置空间的基础。之后,如果您找到一个PCIDMA控制器,您可以使用该控制器的特定寄存器来触发对硬盘的读/写周期。

我们应该如何分配页面以供应用程序使用?

您需要一种算法来确定进程在物理内存中的着陆位置。启动进程时,Linux使用伙伴算法查找未分配的页面,以避免外部碎片。您操作系统的编译器/链接器应该已经将编译后的程序拆分成页面(这是由ld和g++/GCC完成的)。

这篇关于寻呼到底是什么?OSDEV的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆