当前位置: 首页 > news >正文

[OS] sys_mmap() 函数+

流程图分析

1. 调用 sys_mmap()
  • 步骤:当用户程序调用 mmap() 时,操作系统会进入 sys_mmap() 函数。
  • 作用:这是整个 mmap() 操作的入口。系统调用的实现从这里开始。
2. 提取参数(Fetch Argument)
  • 步骤:从用户传递的系统调用中提取参数,例如映射的地址、长度、权限等。
  • 作用:确保 mmap() 调用收到的参数正确无误,并且提取用户传递的所有必要信息。
  • 错误处理:如果参数无效(例如,值无效或权限冲突),则返回错误 -1,表示 mmap() 失败。
3. 查找空闲的 VMA(Find a Free VMA)
  • 步骤:在当前进程的 VMA 列表中查找一个可用的 VMA 槽位,来存储新的映射信息。
  • 作用:每个 VMA 代表一个虚拟内存区域,系统通过这个步骤为新的映射区域找到一个合适的位置。
  • 错误处理:如果没有可用的 VMA 槽位,则 panic("syscall mmap"),表示系统找不到可用的映射区域。这种情况通常不会出现,除非进程的 VMA 数量达到上限。
4. 将信息记录到 VMA 结构中(Record Infos to VMA Structs)
  • 步骤:将用户传递的参数(如起始地址、长度、权限等)记录到找到的 VMA 结构体中。
  • 作用:将映射的相关信息存储在 VMA 中,便于操作系统后续管理和维护这个映射区域。
  • 备注:这是 sys_mmap() 的核心步骤,确保进程中的 VMA 列表保存了每个映射的详细信息。
5. 增加文件的引用计数(filedup)
  • 步骤:调用 filedup() 函数,增加文件的引用计数。
  • 作用:表示这个文件有新的映射,确保文件在映射存在期间不会被删除或关闭。
  • 备注:这一步是为了保证文件的一致性和安全性。引用计数的增加确保文件资源在映射期间被正确管理。
6. 返回虚拟地址(return virtual address)
  • 步骤sys_mmap() 返回映射区域的起始虚拟地址给调用的用户程序。
  • 作用:让用户程序知道映射区域的位置,以便可以直接访问映射的数据。
  • 备注:这是 mmap() 调用的结果,用户程序可以通过返回的虚拟地址来访问文件内容。

关键步骤总结

  • 参数检查:确保用户传递的参数合法,防止错误的映射请求。
  • VMA 分配:从进程的 VMA 列表中找到一个空闲的槽位,记录映射信息。
  • 文件引用管理:通过增加文件的引用计数,确保文件在映射期间不会被其他进程关闭。
  • 返回映射地址:返回给用户一个虚拟地址,表示映射成功,方便用户直接访问映射的内存。

通俗解释

可以将这个流程想象成系统为用户程序分配一块“内存空间”的过程:

  1. 检查请求是否合理:先检查用户的请求是否符合要求(例如,要的内存大小、权限等)。
  2. 找到空位:在进程的 VMA 列表中找到一个空闲的位置,类似找到一张空桌子。
  3. 记录信息:把请求的内容记在这个位置上,确保以后系统知道这是用户申请的映射区域。
  4. 确保资源不被误用:增加文件的引用计数,确保这个文件不会在映射期间被其他操作关闭或修改。
  5. 返回地址:最后,把这块分配的空间地址返回给用户,方便用户直接使用。

实现的关键点

在实现 sys_mmap() 时,您需要关注以下几点:

  • 参数验证:确保所有传入参数合法,包括地址、权限和大小等。
  • VMA 分配逻辑:遍历 VMA 数组,找到一个空闲的 VMA,如果没有找到,返回错误。
  • 记录映射信息:根据参数设置 VMA 结构体的各字段。
  • 文件引用计数管理:调用 filedup() 增加文件的引用计数,保证文件在映射期间的有效性。
  • 返回虚拟地址:最终返回映射区域的地址,供用户直接访问。

 

从图片中可以看出,在 sys_mmap 的实现过程中,需要从系统调用中获取传递的参数,而这些参数是通过 trapframe 来存储的。以下是对这个过程的详细分析。

关键问题

问题:如何获取 sys_mmap 的参数?

sys_mmap 的实现中,我们并没有直接从函数的参数列表中看到用户传递的参数(例如,地址、长度、权限等)。那么,如何从系统调用中获取这些参数呢?

答案:利用 trapframe

在 xv6 操作系统中,系统调用的参数是通过 trapframe 结构体来存储的。trapframe 是每个进程在发生系统调用或中断时,存储 CPU 寄存器状态的结构体。参数会被传递到特定的寄存器中,然后被 trapframe 捕获和存储。

proc 结构体中,每个进程都有一个 trapframe,其中包含了这些系统调用参数的寄存器值。因此,我们可以通过访问 trapframe 中的特定字段(例如 a0a5)来获取这些参数。

arghraw() 函数的作用

代码右侧显示了一个函数 argraw(int n),它用于从当前进程的 trapframe 中获取参数:

static uint64 arghraw(int n) {struct proc *p = myproc();switch (n) {case 0: return p->trapframe->a0;case 1: return p->trapframe->a1;case 2: return p->trapframe->a2;case 3: return p->trapframe->a3;case 4: return p->trapframe->a4;case 5: return p->trapframe->a5;}panic("arghraw");return -1;
}
作用分析
  • 参数索引arghraw() 函数接受一个整数 n,代表参数的索引。系统调用中最多可以传递 6 个参数(a0a5)。
  • 获取参数值:函数通过 switch 语句,根据参数的索引值 n,返回 trapframe 中对应的寄存器值。这些寄存器保存了系统调用时传入的参数值。
  • 错误处理:如果 n 超出范围,函数会触发 panic,表示参数获取失败。

具体步骤

在实现 sys_mmap 时,可以通过调用 arghraw(n) 来获取每个参数。例如:

uint64 addr = arghraw(0);   // 获取地址参数
size_t length = arghraw(1); // 获取长度参数
int prot = arghraw(2);      // 获取权限参数
int flags = arghraw(3);     // 获取标志参数
int fd = arghraw(4);        // 获取文件描述符参数
off_t offset = arghraw(5);  // 获取偏移量参数

 

总结

  • trapframe 记录了系统调用的参数值,参数存储在寄存器中。
  • 通过 arghraw() 函数,可以从 trapframe 中按索引顺序提取参数,以便在 sys_mmap 中使用。
  • arghraw()switch 语句确保了可以灵活获取从 a0a5 的任意一个参数值。

通俗解释

可以把 trapframe 想象成进程的“快照记录本”。当系统调用发生时,操作系统会将参数值保存在 “记录本” 中的特定位置(即寄存器 a0a5)。arghraw() 就像一个“翻页函数”,根据参数的顺序翻到对应的寄存器位置,读取参数值,然后返回给系统调用。

 

1. 什么是 trapframe

trapframe 是一个结构体,用于保存进程在发生系统调用中断异常时的 CPU 寄存器状态。可以把它想象成操作系统在处理系统调用或中断时,记录当前进程状态的“备忘录”。

当程序发生系统调用或中断时,CPU 的寄存器会被用来传递参数和执行控制流切换。为了在系统调用处理完后能够让程序继续执行,操作系统会在进入内核之前把寄存器状态(包括系统调用的参数)保存到 trapframe 中。这样,在完成系统调用后,操作系统可以恢复寄存器状态,让程序从中断前的状态继续运行。

2. trapframe 从哪里来?

在 xv6 等操作系统中,每个进程都有一个独立的 trapframe,它是进程控制块(即 proc 结构体)的一部分。proc 结构体中的 trapframe 指针指向了保存当前进程状态的 trapframe

  1. 创建进程时:操作系统会为每个进程分配一个 trapframe
  2. 系统调用或中断发生时:操作系统会将当前 CPU 寄存器的值保存到 trapframe 中,以备稍后恢复。
  3. 系统调用处理完成后:操作系统将 trapframe 中保存的寄存器状态恢复到 CPU 中,继续执行进程。

3. trapframe 的作用是什么?

trapframe 的主要作用是在进程进入内核态时保存其状态。具体作用如下:

  • 保存寄存器状态:在进入系统调用或中断时,CPU 寄存器的值会被存储到 trapframe 中,包括系统调用传递的参数、程序计数器等。
  • 恢复现场:在系统调用完成后,操作系统会将 trapframe 中的状态恢复到 CPU 寄存器,让进程继续执行。

4. trapframesys_mmap 的关系

sys_mmap 中,我们需要获取用户传递的参数,而这些参数在系统调用发生时被保存在 trapframe 的寄存器字段中。具体来说:

  • 当用户调用 mmap() 时,传递的参数会存储在寄存器 a0a5 中(因为 RISC-V 架构的系统调用参数通过这几个寄存器传递)。
  • 操作系统会将这些寄存器值存储在 trapframe 的相应字段中。
  • sys_mmap 可以通过 proc 结构体中的 trapframe 指针,读取寄存器中的参数值,完成系统调用所需的操作。

5. argraw 函数如何使用 trapframe

sys_mmap 中,我们使用 argraw 函数从 trapframe 中提取系统调用的参数值。

static uint64 arghraw(int n) {struct proc *p = myproc(); // 获取当前进程的 proc 结构体switch (n) {case 0: return p->trapframe->a0;case 1: return p->trapframe->a1;case 2: return p->trapframe->a2;case 3: return p->trapframe->a3;case 4: return p->trapframe->a4;case 5: return p->trapframe->a5;}panic("arghraw");return -1;
}
  • 步骤
    1. arghraw 函数通过 myproc() 获取当前进程的 proc 结构体。
    2. proc 结构体中有一个指向 trapframe 的指针,通过它可以访问系统调用参数。
    3. switch 语句根据参数的顺序 n,返回 trapframe 中相应的寄存器值(即参数值)。

6. 通俗解释

可以将 trapframe 想象成一个“暂停存储器”。当程序进入内核,发生系统调用时,操作系统会将程序的寄存器状态保存到 trapframe,相当于“暂停”了程序。等系统调用执行完毕,操作系统会使用 trapframe 中的信息,将程序恢复到调用前的状态,相当于“继续”运行程序。

  • 为什么 trapframe 重要? 因为系统调用是程序和操作系统交互的桥梁,而 trapframe 确保了程序在交互过程中不会丢失任何状态。
  • sys_mmaptrapframe 的关系sys_mmap 是一种系统调用,它的参数通过 trapframe 保存,sys_mmap 可以通过 trapframe 获取这些参数。

总结

  • trapframe 是一个寄存器状态的备份,每次系统调用都会更新它。
  • trapframeproc 结构体的一部分,可以通过 proc 获取它。
  • sys_mmap 中,通过 trapframe 获取系统调用参数,确保正确执行 mmap 操作。

 


http://www.mrgr.cn/news/65813.html

相关文章:

  • 初识动态规划(由浅入深)
  • 在线PDF转图片网站
  • GitHub中搜索项目方法
  • 分析自动下载电路是如何工作的以及CH340的选型
  • 【django】django RESTFramework前后端分离框架快速入门
  • stm32cubeIde 使用笔记
  • FFMPEG录屏(21)--- Linux 下基于X11枚举所有可见窗口,并获取标题、图标、缩略图、进程路径等信息
  • 基于python flask的知乎问答文本分析与情感预测系统
  • Android使用scheme方式唤醒处于后台时的App场景
  • 【C++】继承的理解
  • 电脑虚拟机启动树莓派rviz
  • 【c++篇】:深入剖析vector--模拟实现属于自己的c++动态数组
  • SVD求解ICP旋转矩阵不正确处理
  • WorkFlow源码剖析——Communicator之TCPServer(中)
  • SpringBoot源码解析(一)
  • 响应式编程-reactor
  • 动态内存分配
  • 使用 pytorch 运行预训练模型的框架
  • FFmpeg 4.3 音视频-多路H265监控录放C++开发十二:在屏幕上显示多路视频播放,可以有不同的分辨率,格式和帧率。
  • HTB:Shocker[WriteUP]
  • 如何在BSV区块链上实现可验证AI
  • 隆盛策略股票杠杆交易市场罕见,26只“牛股”提示风险
  • VSCode 1.82之后的vscode server离线安装
  • Centos使用yum获取离线安装包
  • springboot 单元测试-各个模块举例
  • 爱奇艺大数据多AZ统一调度架构:打破数据孤岛,提升效率