ucore 清华实验物理内存篇

  • 理解基于段页式内存地址的转换机制

  • 理解页表的建立和使用方法

  • 理解物理内存的管理方法

手动实现简易的物理内存管理系统

基本的函数

default_pmm_manager 的结构体变量,类型为 struct pmm_manager。这个结构体变量包含了默认的物理内存管理器的信息和功能。

具体来说,它的意思如下:

  • .name = "default_pmm_manager":给物理内存管理器取了一个名字,即 "defaultpmmmanager"。

  • .init = default_init:指定了初始化函数,即 default_init 函数,用于初始化物理内存管理器。

  • .init_memmap = default_init_memmap:指定了初始化内存映射的函数,即 default_init_memmap 函数,用于初始化空闲物理页的映射。

  • .alloc_pages = default_alloc_pages:指定了分配内存页的函数,即 default_alloc_pages 函数,用于从物理内存中分配一页或多页的内存。

  • .free_pages = default_free_pages:指定了释放内存页的函数,即 default_free_pages 函数,用于将不再使用的内存页释放回物理内存。

  • .nr_free_pages = default_nr_free_pages:指定了获取空闲内存页数量的函数,即 default_nr_free_pages 函数,用于获取当前物理内存中的空闲页数量。

  • .check = default_check:指定了检查函数,即 default_check 函数,用于检查物理内存管理器的正确性。

  1. 首次适应分配算法 实现 first-fit 连续物理内存分配算法

首先

假设我们有一段连续的内存,通过 default_init_memmap() 函数初始化为以下状态:

```Plain Text plaintextCopy code +-------------------+ | Free (nrfree) | +-------------------+ ^ ^ | | freelist End

复制代码
### `static struct Page * default_alloc_pages(size_t n)` 此函数为分配空闲页

让我们通过图示来解释代码的执行过程。

假设我们有一个空闲页链表,如下所示:

+-------+ +-------+ +-------+ +-------+

| Page1 | | Page2 | | Page3 | | Page4 |

+-------+ +-------+ +-------+ +-------+

4页 3页 5页 2页

复制代码
每个空闲页都有一个属性 `property` 记录了它的大小。

现在,假设我们调用 `default_alloc_pages(4)`,希望分配一个大小为 4 页的空闲块。

代码执行过程如下:

2. **初始化**:我们初始化一个指针 `le` 指向空闲页链表的头部。

3. **遍历空闲页链表**:我们开始从头部遍历空闲页链表,寻找一个大小大于等于 4 页的空闲块。

4. **找到合适的空闲块**:假设在遍历过程中,我们找到了 `Page3`,它的大小为 5 页。

+-------+ +-------+ +-------+ |

Page1 | | Page2 | | Page4 |

+-------+ +-------+ +-------+

4页 3页 2页

复制代码
5. **分配空闲块**:我们将 `Page3` 分配出去,并从空闲页链表中删除。

+-------+ +-------+ +-------+ |

Page1 | | Page2 | | Page4 |

+-------+ +-------+ +-------+

4页 3页 2页

复制代码
6. **更新空闲页链表**:由于 `Page3` 的大小超过了需要的 4 页,因此我们需要将剩余的部分重新加入到空闲页链表中。

+-------+ +-------+ +-------+ +-------+ |

Page1 | | Page2 | | Page3 | | Page4 |

+-------+ +-------+ +-------+ +-------+

4页 3页 1页 2页

复制代码
这样,我们就完成了一次内存分配的过程。整个过程中,代码按照从头部开始的顺序遍历空闲页链表,找到了第一个大小满足要求的空闲块,并进行了相应的分配操作。



### 即 `default_free_pages` 函数,用于将不再使用的内存页释放回物理内存。

给定内存中包含的页以及释放内存的情况,如下所示:

+-------+-------+-------+-------+-------+-------+ |

Page1 | Page2 | Page3 | Page4 | Page5 | Page6 |

+-------+-------+-------+-------+-------+-------+

复制代码
假设我们要释放从 `Page2` 开始的 3 页内存。

7. **初始状态**:在初始状态下,我们有六个页,每个页都是可用的。

+-------+-------+-------+-------+-------+-------+

| Page1 | Page2 | Page3 | Page4 | Page5 | Page6 |

+-------+-------+-------+-------+-------+-------+

复制代码
8. **释放内存页**:我们从 `Page2` 开始释放 3 页内存,并将它们标记为可用。

+-------+-------+-------+-------+-------+-------+ |

Page1 | Free | Free | Free | Page5 | Page6 |

+-------+-------+-------+-------+-------+-------+ ```

  1. 合并连续的空闲页:由于释放的内存页与相邻的空闲页相连,因此我们将它们合并为一个更大的空闲页。

即一整个free空闲页

default_nr_free_pages:指定了获取空闲内存页数量的函数

static size_t

defaultnrfree_pages(void) {

return nr_free;

}

实现寻找虚拟地址对应的页表项

页目录项(Page Directory Entry)和页表项(Page Table Entry)是 x86 架构下操作系统管理虚拟内存的重要数据结构。

页目录项(Page Directory Entry):

  • Present (P):表示页目录项是否存在,用于判断页表是否存在于内存中。

  • Read/Write (R/W):表示页表对应的页面是否可读写,用于设置页表权限。

  • User/Supervisor (U/S):表示页表对应的页面是否可供用户态程序访问,用于设置页表权限。

  • Accessed (A):表示该页表项是否被访问过,用于页面置换算法。

  • Dirty (D):表示该页表对应的页面是否被修改过,用于页面置换算法和页面写回判断。

  • Page Table Base Address (PTBA):存储页表的物理地址,指向页表的起始地址。

页表项(Page Table Entry):

  • Present (P):表示页表项是否存在,用于判断物理页面是否存在于内存中。

  • Read/Write (R/W):表示物理页面是否可读写,用于设置页面权限。

  • User/Supervisor (U/S):表示物理页面是否可供用户态程序访问,用于设置页面权限。

  • Accessed (A):表示该页表项对应的页面是否被访问过,用于页面置换算法。

  • Dirty (D):表示该页表对应的页面是否被修改过,用于页面置换算法和页面写回判断。

  • Page Base Address (PBA):存储物理页面的起始地址。

当ucore执行过程中访问内存出现页访问异常时,硬件会进行以下处理:

  1. 检查页目录项和页表项中的标志位,如Present、Read/Write、User/Supervisor等,确定访问权限。

  2. 如果页表项或页目录项不存在,会引发页错误异常(Page Fault Exception)。

  3. 操作系统会根据页错误异常的处理机制,将缺失的页面从磁盘加载到内存中,更新页表项,并重新执行引发异常的指令。

释放某虚地址所在的页并取消对应二级页表项的映射

当释放一个包含某虚地址的物理内存页时,需要让对应此物理内存页的管理数据结构 Page 做相关的清除处理,使得此物理内存页成为空闲;另外还需把表示虚地址与物理地址对应关系的二级页表项清除

相关推荐
纪元A梦10 小时前
贪心算法应用:K-Means++初始化详解
算法·贪心算法·kmeans
_不会dp不改名_10 小时前
leetcode_21 合并两个有序链表
算法·leetcode·链表
mark-puls11 小时前
C语言打印爱心
c语言·开发语言·算法
Python技术极客11 小时前
将 Python 应用打包成 exe 软件,仅需一行代码搞定!
算法
睡不醒的kun11 小时前
leetcode算法刷题的第三十四天
数据结构·c++·算法·leetcode·职场和发展·贪心算法·动态规划
吃着火锅x唱着歌11 小时前
LeetCode 978.最长湍流子数组
数据结构·算法·leetcode
我星期八休息12 小时前
深入理解跳表(Skip List):原理、实现与应用
开发语言·数据结构·人工智能·python·算法·list
lingran__12 小时前
速通ACM省铜第四天 赋源码(G-C-D, Unlucky!)
c++·算法
haogexiaole12 小时前
贪心算法python
算法·贪心算法
希望201712 小时前
图论基础知识
算法·图论