实验名称:地址映射与共享
实验日期:2022年5月27日
班级:软嵌201 姓名:邓浩礼 学号:2030110734
一、实验目的
深入理解操作系统的段、页式内存管理,深入理解段表、页表、逻辑地址、线性地址、物理地址等概念;
实践段、页式内存管理的地址映射过程;
编程实现段、页式内存管理上的内存共享,从而深入理解操作系统的内存管理。
二、实验环境
本操作系统实验的硬件环境是 IA-32(x86) 架构的 PC 机(在实验楼的环境中就是右侧的窗口),主要软件环境是 Bochs + gcc + 你最喜欢的编辑器 / IDE + 你最喜欢的操作系统 + Linux 0.11 源代码。
三、实验内容
本次实验的基本内容是:
用 Bochs 调试工具跟踪 Linux 0.11 的地址翻译(地址映射)过程,了解 IA-32 和 Linux 0.11 的内存管理机制;
在 Ubuntu 上编写多进程的生产者—消费者程序,用共享内存做缓冲区;
在信号量实验的基础上,为 Linux 0.11 增加共享内存功能,并将生产者—消费者程序移植到 Linux 0.11。
3.1 跟踪地址翻译过程
首先以汇编级调试的方式启动 Bochs,引导 Linux 0.11,在 0.11 下编译和运行 test.c。它是一个无限循环的程序,永远不会主动退出。然后在调试器中通过查看各项系统参数,从逻辑地址、LDT 表、GDT 表、线性地址到页表,计算出变量 i 的物理地址。最后通过直接修改物理内存的方式让 test.c 退出运行。
test.c 的代码如下:
int i = 0x12345678;
int main(void)
{
printf("The logical/virtual address of i is 0x%08x", &i);
fflush(stdout);
while (i)
;
return 0;
copy
}
3.2 基于共享内存的生产者—消费者程序
本项实验在 Ubuntu 下完成,与信号量实验中的 pc.c 的功能要求基本一致,仅有两点不同:
不用文件做缓冲区,而是使用共享内存;
生产者和消费者分别是不同的程序。生产者是 producer.c,消费者是 consumer.c。两个程序都是单进程的,通过信号量和缓冲区进行通信。
Linux 下,可以通过 shmget() 和 shmat() 两个系统调用使用共享内存。
3.3 共享内存的实现
进程之间可以通过页共享进行通信,被共享的页叫做共享内存,结构如下图所示:
图 1 进程间共享内存的结构
本部分实验内容是在 Linux 0.11 上实现上述页面共享,并将上一部分实现的 producer.c 和 consumer.c 移植过来,验证页面共享的有效性。
具体要求在 mm/shm.c 中实现 shmget() 和 shmat() 两个系统调用。它们能支持 producer.c 和 consumer.c 的运行即可,不需要完整地实现 POSIX 所规定的功能。
shmget()
int shmget(key_t key, size_t size, int shmflg);
shmget() 会新建/打开一页内存,并返回该页共享内存的 shmid(该块共享内存在操作系统内部的 id)。
所有使用同一块共享内存的进程都要使用相同的 key 参数。
如果 key 所对应的共享内存已经建立,则直接返回 shmid。如果 size 超过一页内存的大小,返回 -1,并置 errno 为 EINVAL。如果系统无空闲内存,返回 -1,并置 errno 为 ENOMEM。
shmflg 参数可忽略。
shmat()
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmat() 会将 shmid 指定的共享页面映射到当前进程的虚拟地址空间中,并将其首地址返回。
如果 shmid 非法,返回 -1,并置 errno 为 EINVAL。
shmaddr 和 shmflg 参数可忽略。
四、实验过程及数据记录
环境准备
1.创建test.c
挂载 hdc 文件系统,然后切换到用户文件夹编写 test.c 。
使用 sudo umount hdc 命令退出挂载
2.跟踪地址翻译过程
3.添加系统调用号
在 oslab/linux-0.11/include 目录下的 unistd.h 中添加下面代码:
增加两个系统调用。
4.添加系统调用的定义
在 oslab/linux-0.11/include/linux 目录下的 sys.h 中添加函数声明。
5.改写系统调用数
在 oslab/linux-0.11/kernel 目录下的 system_call.s 中修改系统调用数量。
6.编写shm.c
在 oslab/linux-0.11/kernel 目录下创建 shm.c 文件。
7.修改工程文件的编译规则
在 oslab/linux-0.11/kernel 目录下修改 Makefile 文件。
8.编写消费者和生产者程序
在 oslab/hdc/usr/root 目录下创建 producer.c 和 consumer.c 文件
五、实验结果分析
对于地址映射实验部分,列出你认为最重要的那几步(不超过 4 步),并给出你获得的实验数据。
回答:
第一步为找到需要的各个选择符,DS:S=0X0017,LDT:s=0x0068,GDT:BASE=0X0000 5CB8。第二步为找到数据段的基址。实验中进程的NR为4,即第5个进程,所以按照LINUX 0.11的设计,其基址应为 4*64M,转换为16进制即为0x1000 0000。实验结果也验证了这一点。第三步根据找到的线性地址,通过查看页目录表就可以找到对应页表的物理地地址。实验中页表的物理地址为0x00fa 70000。 第四步根据找到的页表所对就应的物理地址就可以找到变量所在页的物理地址。实验中变量所在页的物理地址为0x00fa6000。这里有个很有趣的现象,页表的物理地址比具体一页的物理地址高。而页表一定是先分配的内存,这也说明linux 0.11中物理内存的分配是从高到低进行的。这一点通过查看get_free_page函数得到印证。
test.c 退出后,如果马上再运行一次,并再进行地址跟踪,你发现有哪些异同?为什么?
回答:
若马上再运行一次,则可以看到得到的线性地址为0x1400 3004,即进程的数据段基地多了0x0400 0000。就是多了一个64M。这也正是linux 0.11中对进程线性地址分配的方法即:nr*64M。因为马上运行此时进程4并没有被删除,而只是状态个性为3,所以再运行的进程正好是5。所以其分配的线性地址基址为0x1400 0000。
学习时间 63分钟
操作时间 27分钟
按键次数 392次
实验次数 2次
报告字数 4649字
是否完成 完成