操作系统实战 45 讲
彭东
网名 LMOS,Intel 傲腾项目关键开发者
65203 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 60 讲
尝尝鲜:从一个Hello到另一个Hello (2讲)
特别放送 (1讲)
操作系统实战 45 讲
15
15
1.0x
00:00/00:00
登录|注册

21 | 土地需求扩大与保障:如何分配和释放虚拟内存?

处理缺页异常
虚拟地址空间的分配与释放
虚拟内存管理

该思维导图由 AI 生成,仅供参考

你好,我是 LMOS。
今天,我们继续研究操作系统如何实现虚拟内存。在上节课,我们已经建立了虚拟内存的初始流程,这节课我们来实现虚拟内存的核心功能:写出分配、释放虚拟地址空间的代码,最后实现虚拟地址空间到物理地址空间的映射。
这节课的配套代码,你可以点击这里下载。

虚拟地址的空间的分配与释放

通过上节课的学习,我们知道整个虚拟地址空间就是由一个个虚拟地址区间组成的。那么不难猜到,分配一个虚拟地址空间就是在整个虚拟地址空间分割出一个区域,而释放一块虚拟地址空间,就是把这个区域合并到整个虚拟地址空间中去。

虚拟地址空间分配接口

我们先来研究地址的分配,依然从虚拟地址空间的分配接口开始实现,一步步带着你完成虚拟 空间的分配。
在我们的想像中,分配虚拟地址空间应该有大小、有类型、有相关标志,还有从哪里开始分配等信息。根据这些信息,我们在 krlvadrsmem.c 文件中设计好分配虚拟地址空间的接口,如下所示。
adr_t vma_new_vadrs_core(mmadrsdsc_t *mm, adr_t start, size_t vassize, u64_t vaslimits, u32_t vastype)
{
adr_t retadrs = NULL;
kmvarsdsc_t *newkmvd = NULL, *currkmvd = NULL;
virmemadrs_t *vma = &mm->msd_virmemadrs;
knl_spinlock(&vma->vs_lock);
//查找虚拟地址区间
currkmvd = vma_find_kmvarsdsc(vma, start, vassize);
if (NULL == currkmvd)
{
retadrs = NULL;
goto out;
}
//进行虚拟地址区间进行检查看能否复用这个数据结构
if (((NULL == start) || (start == currkmvd->kva_end)) && (vaslimits == currkmvd->kva_limits) && (vastype == currkmvd->kva_maptype))
{//能复用的话,当前虚拟地址区间的结束地址返回
retadrs = currkmvd->kva_end;
//扩展当前虚拟地址区间的结束地址为分配虚拟地址区间的大小
currkmvd->kva_end += vassize;
vma->vs_currkmvdsc = currkmvd;
goto out;
}
//建立一个新的kmvarsdsc_t虚拟地址区间结构
newkmvd = new_kmvarsdsc();
if (NULL == newkmvd)
{
retadrs = NULL;
goto out;
}
//如果分配的开始地址为NULL就由系统动态决定
if (NULL == start)
{//当然是接着当前虚拟地址区间之后开始
newkmvd->kva_start = currkmvd->kva_end;
}
else
{//否则这个新的虚拟地址区间的开始就是请求分配的开始地址
newkmvd->kva_start = start;
}
//设置新的虚拟地址区间的结束地址
newkmvd->kva_end = newkmvd->kva_start + vassize;
newkmvd->kva_limits = vaslimits;
newkmvd->kva_maptype = vastype;
newkmvd->kva_mcstruct = vma;
vma->vs_currkmvdsc = newkmvd;
//将新的虚拟地址区间加入到virmemadrs_t结构中
list_add(&newkmvd->kva_list, &currkmvd->kva_list);
//看看新的虚拟地址区间是否是最后一个
if (list_is_last(&newkmvd->kva_list, &vma->vs_list) == TRUE)
{
vma->vs_endkmvdsc = newkmvd;
}
//返回新的虚拟地址区间的开始地址
retadrs = newkmvd->kva_start;
out:
knl_spinunlock(&vma->vs_lock);
return retadrs;
}
//分配虚拟地址空间的接口
adr_t vma_new_vadrs(mmadrsdsc_t *mm, adr_t start, size_t vassize, u64_t vaslimits, u32_t vastype)
{
if (NULL == mm || 1 > vassize)
{
return NULL;
}
if (NULL != start)
{//进行参数检查,开始地址要和页面(4KB)对齐,结束地址不能超过整个虚拟地址空间
if (((start & 0xfff) != 0) || (0x1000 > start) || (USER_VIRTUAL_ADDRESS_END < (start + vassize)))
{
return NULL;
}
}
//调用虚拟地址空间分配的核心函数
return vma_new_vadrs_core(mm, start, VADSZ_ALIGN(vassize), vaslimits, vastype);
}
上述代码中依然是接口函数进行参数检查,然后调用核心函数完成实际的工作。在核心函数中,会调用 vma_find_kmvarsdsc 函数去查找 virmemadrs_t 结构中的所有 kmvarsdsc_t 结构,找出合适的虚拟地址区间。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了操作系统中虚拟内存的分配和释放功能的实现。首先详细讲解了虚拟地址空间的分配接口的实现,包括对虚拟地址空间大小、类型、标志以及开始地址的处理。接着展示了分配时查找虚拟地址区间的算法和代码实现。文章通过代码和注释的形式展现了虚拟内存管理的核心功能,对于想深入了解操作系统内存管理的读者来说,是一篇很有价值的技术文章。文章还介绍了释放虚拟地址空间的核心处理函数和释放时查找虚拟地址区间的函数,以及对虚拟地址空间进行访问的测试。整体而言,本文内容丰富,对于想深入了解操作系统内存管理的读者具有很高的参考价值。文章通过实例代码和详细解释,展示了虚拟内存管理的核心功能,对读者深入理解操作系统内存管理提供了很好的帮助。文章还介绍了处理缺页异常的核心功能,包括判断缺页地址的合法性、建立kvmemcbox_t结构等操作。整体而言,本文对于想深入了解操作系统内存管理的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《操作系统实战 45 讲》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(21)

  • 最新
  • 精选
  • neohope
    置顶
    一、整理一下结构 1、进程的内存地址空间用一个 mmadrsdsc_t结构表示 2、mmadrsdsc_t结构中包括一个virmemadrs_t结构,管理了进程全部kmvarsdsc_t结构【虚拟地址空间】 3、每个kmvarsdsc_t【虚拟地址空间】,都包括一个kvmemcbox_t结构【页面盒子】 4、每个kvmemcbox_t【页面盒子】,管理虚拟地址空间与物理内存页面的关系,并记录了物理内存页面对应的 msadsc_t 结构【页面】 5、每个msadsc_t结构,是一个页面 6、为了管理方便,操作系统有一个全局kvmemcboxmgr_t结构,统一管理全部kvmemcbox_t 二、虚拟地址空间分配 vma_new_vadrs -> vma_new_vadrs_core ->-> vma_find_kmvarsdsc 1、查找合适的 kmvarsdsc_t结构 2、如果可以复用找到的kmvarsdsc_t结构,扩容 3、如果无法复用,创建新的kmvarsdsc_t结构,加入到 virmemadrs_t【按地址有序】 其中,vma_find_kmvarsdsc->vma_find_kmvarsdsc_is_ok的查找过程为 依次检查virmemadrs_t中全部 kmvarsdsc_t结构: 1、如果没有指定起始地址,则判断当前kmvarsdsc_t与下一个kmvarsdsc_t之间,是否有未分配的虚拟地址,长度满足要求 2、如果制定了起始地址,则判断当前kmvarsdsc_t与 下一个kmvarsdsc_t之间,,是否有未分配的虚拟地址,起始地址和长度都满足要求 三、虚拟地址空间释放 vma_del_vadrs ->vma_del_vadrs_core ->->vma_del_find_kmvarsdsc 根据起始地址,查找要释放虚拟地址空间的kmvarsdsc_t结构; 根据要释放的空间与kmvarsdsc_t结构起始地址有四种情况: A、首位都相等,砍掉kmvarsdsc_t结构 B、开始相等,砍掉kmvarsdsc_t开始 C、结尾相等,砍掉kmvarsdsc_t结尾 D、首尾都不相等,砍掉中间部分,两边拆分为两个kmvarsdsc_t结构 四、缺页中断 应用程序访问没有分配页面的虚拟地址,触发缺页中断 SRFTFAULT_ECODE 14 ->hal_fault_allocator异常分发 ->->krluserspace_accessfailed->vma_map_fairvadrs->vma_map_fairvadrs_core缺页中断处理: 1、vma_map_find_kmvarsdsc找到对应的kmvarsdsc_t结构 2、vma_map_retn_kvmemcbox返回 kmvarsdsc_t 结构的 kvmemcbox_t 结构,没有就新建一个 3、vma_map_phyadrs->vma_map_msa_fault分配物理内存页面,并建立 MMU 页表映射关系 4、此时,应用程序就可以访问该虚拟地址了

    作者回复: 高手就是高手 大写6666

    2021-06-27
    4
    30
  • pedro
    代码已经告诉我们一切: //如果异常号等于14则是内存缺页异常 if (faultnumb == 14) //打印缺页地址,这地址保存在CPU的CR2寄存器中

    作者回复: 哈哈,你真机智

    2021-06-25
    2
    14
  • springXu
    对于提的两道问题,其实仔细看本课异常处理的代码(文中能找到)部分,就能知道答案了。变成了一个阅读理解题。东哥是为了让我们认真看文章,而且也增加了评论区的活跃度。哈

    作者回复: 哈哈 正确

    2021-06-25
    3
  • ifelse
    我都直接跳过代码部分

    编辑回复: 二刷的时候可以品品代码~

    2022-02-16
    2
    2
  • 相逢是缘
    越来越难啊

    编辑回复: 内存是内核的内核,挺过去就好啦~

    2021-06-27
    2
  • Geek5167
    虚拟内存地址分配时,如果申请的空间大于4kb,虚拟内存是不是只能分配8kb,16kb这样的大小?

    作者回复: 是的

    2022-01-10
    1
  • Dingo
    十几分钟的课程,一看就是大半天。

    作者回复: 哈哈

    2021-11-10
    2
    1
  • 不修竹
    讲得相当清晰了,一学一整天真是痛快~

    编辑回复: 感谢你的认可,也给你的学习劲头点赞,后面更精彩!

    2021-08-16
    1
  • 沐多
    代码里看到缺页异常是14号,地址保存在cr2寄存器中。

    作者回复: 是的

    2021-06-25
    1
  • jshen28
    请问变量名是什么意思呢?是如何缩写的呢?

    作者回复: 那一个呢

    2022-08-06归属地:湖北
收起评论
显示
设置
留言
21
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部