type
Post
status
Published
slug
2023/07/17/put_page-function-in-Linux-0.11
summary
tags
Linux
开发
category
Linux
icon
password
new update day
Property
Oct 22, 2023 01:31 PM
created days
Last edited time
Oct 22, 2023 01:31 PM
put_page
是 Linux 0.11 内核中的一个函数,它用于将物理内存页面映射到进程的虚拟地址空间中。它接受两个参数:page
和 address
。page
是要映射的物理页面的地址,而 address
是要映射到的虚拟地址。下面是
put_page
函数在 Linux 0.11 中的实现(位于 linux/mm/memory.c
文件中):unsigned long put_page(unsigned long page,unsigned long address) { unsigned long tmp, *page_table; // address>>20&ffc存放的是页目录的地址。 // 此操作相当于把page_table设置为指向该页目录项的指针 page_table = (unsigned long *) ((address>>20) & 0xffc); // 检查页目录项,即页表地址是否有效。 // 有效的话则把page_table跟上面一样再跳一级,依据页号指向该页目录项对应的页表的第一项; // 无效的话,则新申请一张页表 if ((*page_table) & 1) page_table = (unsigned long *) (0xfffff000 & *page_table); else { tmp = get_free_page(); *page_table = tmp | 7; page_table = (unsigned long *) tmp; } // 将页表视为数组,偏移量为页号,页号从address中取得。 page_table[(address>>12) & 0x3ff] = page | 7; return page; }
该函数首先根据传入的虚拟地址
address
计算出对应的页目录项地址,并将 page_table
指针设置为指向该页目录项。然后检查该页目录项是否有效(即对应的页表是否存在)。如果有效,则将 page_table
指针设置为指向该页目录项对应的页表;否则,使用 get_free_page
函数申请一个新的物理页面作为页表,并将该页表的地址写入页目录项中。接下来,函数根据传入的虚拟地址
address
计算出对应的页表项索引,并将传入的物理页面地址 page
写入该页表项中。最后,返回传入的物理页面地址 page
。一个示例
下面是一个简单的示例,用于解释这行代码的工作原理。
假设我们有一个虚拟地址
address
,其值为 0x12345678
。我们希望将一个物理页面映射到该虚拟地址所在的页面。首先,我们需要计算出该虚拟地址对应的页目录项地址。在 Linux 0.11 中,每个进程都有一个页目录,它是一个包含 1024 个页目录项的数组。每个页目录项占用 4 个字节,用于存储对应页表的地址。
由于每个页目录项占用 4 个字节,因此页目录的总大小为
1024 * 4 = 4096
字节,即 4KB。Linux 0.11 将每个进程的页目录放在其虚拟地址空间的最后 4KB 处,因此页目录的起始地址为 0xfffff000
。现在,我们需要根据虚拟地址
address
计算出对应的页目录项索引。由于每个页表包含 1024 个页表项,每个页表项对应一个页面(大小为 4KB),因此每个页目录项可以映射 1024 * 4KB = 4MB
的虚拟地址空间。因此,我们可以通过将虚拟地址右移 22 位(即除以 2^22 = 4MB
)来计算出对应的页目录项索引。在本例中,虚拟地址
address
的值为 0x12345678
,右移 22 位后得到 0x48
。这意味着我们需要访问第 0x48
个页目录项。由于每个页目录项占用 4 个字节,因此第
0x48
个页目录项的地址为 0xfffff000 + 0x48 * 4 = 0xfffff120
。这就是我们要访问的页目录项的地址。现在让我们回到代码中:
page_table = (unsigned long *) ((address>>20) & 0xffc);
这行代码首先将虚拟地址
address
右移 20 位(即除以 2^20 = 1MB
),然后与 0xffc
进行按位与运算。由于 0xffc = 0b111111111100
,因此这相当于保留了右移后结果的最高 10 位,并将其他位清零。在本例中,虚拟地址
address
的值为 0x12345678
,右移 20 位后得到 0x123
。将其与 0xffc
进行按位与运算后得到 0x120
。这正是我们要访问的页目录项相对于页目录起始地址的偏移量。最后,代码将计算出的偏移量强制转换为指针类型,并赋值给指针变量
page_table
。由于没有指定基地址,因此这里实际上是将偏移量作为绝对地址来使用。由于 Linux 0.11 将每个进程的页目录放在其虚拟地址空间的最后 4KB 处(即起始地址为 0xfffff000
),因此这相当于将指针变量 page_table
设置为指向第 0x48
个页目录项。 欢迎加入“喵星计算机技术研究院”,原创技术文章第一时间推送。
- 作者:tangcuyu
- 链接:https://expoli.tech/articles/2023/07/17/put_page-function-in-Linux-0.11
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章