“操作系统实验”实验报告

地址映射与共享

实验名称:地址映射与共享

实验日期:7.7

班级:物联网194

姓名:舒文杰

学号:1930110734

一、实验目的

深入理解操作系统的段、页式内存管理,深入理解段表、页表、逻辑地址、线性地址、物理地址等概念; 实践段、页式内存管理的地址映射过程; 编程实现段、页式内存管理上的内存共享,从而深入理解操作系统的内存管理。

二、实验环境

本操作系统实验的硬件环境是 IA-32(x86) 架构的 PC 机,主要软件环境是 Bochs + gcc + Linux 0.11 源代码。

三、实验内容

  1. 用 Bochs 调试工具跟踪 Linux 0.11 的地址翻译(地址映射)过程,了解 IA-32 和 Linux 0.11 的内存管理机制;

  2. 在 Ubuntu 上编写多进程的生产者—消费者程序,用共享内存做缓冲区;

  3. 在信号量实验的基础上,为 Linux 0.11 增加共享内存功能,并将生产者—消费者程序移植到 Linux 0.11。

四、实验过程及数据记录

1.准备环境

cd /home/shiyanlou/oslab
tar -zxvf hit-oslab-linux-20110823.tar.gz -C /home/shiyanlou
ls -al
copy

图片描述

2.进入Linux-0.11目录内make编译系统,然后回到oslab目录图片描述

3.挂载hdc文件系统,在usr/root目录内增加test.c文件用于测试地址映射 图片描述 图片描述

4.使用汇编级调试

./dbg-asm
copy

图片描述

输入c开始运行,编译并运行test.c 图片描述

gcc -o test test.c
./test
copy

图片描述

5.进入死循环,按下Ctrl+C暂停bochs进行调试, 图片描述

6.寻找LDT表: GDT(全局描述符表,操作系统使用的段表)中保存着 LDT 的物理地址,而ldtr 寄存器中记录着LDT物理地址在GDT表中的位置。

输入sreg命令后,显示出各寄存器的信息 图片描述 ldtr的值是 0x0068,转换成二进制是0000000001101000,其中1101这四位表示LDT的物理地址在GDT表中的位置,1101转换成十进制是13。 下图中gdtr的值是GDT表的物理地址,即0x00005cb8。

7.用 xp /32w 0x00005cb8 命令查看从GDT表的物理地址开始,32 个单位的内容,即 GDT 表的前 16 项图片描述

8.0x10003004 的页目录号是 64,页号 3,页内偏移是 4。 页目录表的位置由 CR3 寄存器指引。输入“creg”命令可以看到CR3=0x00000000,图片描述

9.此机器对于物理地址为 0x00fa6004 输入setpmem 0x00fa7004 4 0 切回boch界面图片描述

10.修改unistd.h

图片描述

11.sys.h修改 图片描述

12.添加shm.c

图片描述

13.修改Kernel下的Makefile文件

图片描述

14.编写生产者消费者 生产者:

/*producer*/ 
#define __LIBRARY__
#include <stdio.h>
#include <unistd.h>
#include <linux/kernel.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/sem.h>

_syscall2(sem_t *,sem_open,const char *,name,int,value);
_syscall1(int,sem_post,sem_t *,sem);
_syscall1(int,sem_wait,sem_t *,sem);

_syscall1(int, shmat, int, shmid);
_syscall2(int, shmget, unsigned int, key, size_t, size);

#define PRODUCE_NUM 200
#define BUFFER_SIZE 10
#define SHM_KEY 2018

int main(int argc, char* argv[])
{
    sem_t *Empty,*Full,*Mutex;    
    int i, shm_id, location=0;
    int *p;

    Empty = sem_open("Empty", BUFFER_SIZE);
    Full = sem_open("Full", 0);
    Mutex = sem_open("Mutex", 1);

    if((shm_id = shmget(SHM_KEY, BUFFER_SIZE*sizeof(int))) < 0)
        printf("shmget failed!");    

    if((p = (int * )shmat(shm_id)) < 0)
        printf("shmat error!");
    for(i=0; i<PRODUCE_NUM; i++)
    {
        sem_wait(Empty);
        sem_wait(Mutex);

        p[location] = i;

        sem_post(Mutex);
        sem_post(Full);
        location  = (location+1) % BUFFER_SIZE;
    }
    return 0;    
}
copy

消费者:

/*consumer*/ 
#define __LIBRARY__
#include <stdio.h>
#include <unistd.h>
#include <linux/kernel.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/sem.h>

_syscall2(sem_t *,sem_open,const char *,name,int,value);
_syscall1(int,sem_post,sem_t *,sem);
_syscall1(int,sem_wait,sem_t *,sem);
_syscall1(int,sem_unlink,const char*,name);

_syscall1(int, shmat, int, shmid);
_syscall2(int, shmget, unsigned int, key, size_t, size);

#define PRODUCE_NUM 200
#define BUFFER_SIZE 10
#define SHM_KEY 2018

int main(int argc, char* argv[])
{
    sem_t *Empty,*Full,*Mutex;    
    int used = 0, shm_id,location = 0;
    int *p;

    Empty = sem_open("Empty", BUFFER_SIZE);
    Full = sem_open("Full", 0);
    Mutex = sem_open("Mutex", 1);

    if((shm_id = shmget(SHM_KEY, BUFFER_SIZE*sizeof(int))) < 0)
        printf("shmget failed!\n");    

    if((p = (int * )shmat(shm_id)) < 0)
        printf("link error!\n");
    while(1)
    {
        sem_wait(Full);
        sem_wait(Mutex);

        printf("pid %d:\tconsumer consumes item %d\n", getpid(), p[location]);
        fflush(stdout);

        sem_post(Mutex);     
        sem_post(Empty);
        location  = (location+1) % BUFFER_SIZE;

        if(++used == PRODUCE_NUM)
            break;
    }

    sem_unlink("Mutex");
    sem_unlink("Full");
    sem_unlink("Empty");
    return 0;    
}
copy

14.运行bochs,输入: gcc -o pro producer.c gcc -o con consumer.c 编译这两个程序, 然后输入 pro > proOutput & con > conOutput & 来同时运行这两个程序,并将结果保存到proOutput和conOutput中。 最后输入sync。

五、实验结果分析 用 Bochs 调试工具跟踪 Linux 0.11 的地址翻译(地址映射)过程正确,在 Ubuntu 上编写多进程的生产者—消费者程序,用共享内存做缓冲 区,结果正确无误;在信号量实验的基础上,为 Linux 0.11 增加共享内存功能,并将生产者—消费者程序移植到 Linux 0.11,运行结果正确

六、实验心得

问题1.对于地址映射实验部分,列出你认为最重要的那几步(不超过 4 步),并给出你获得的实验数据。

答:1.输入命令u/7反汇编,查看变量i对应的逻辑地址。

2.逻辑地址找虚拟地址要通过段表,也就是IDT表,然后IDT表要根据LDTR寄存器和GDT表,对应的命令就是sreg。

3.根据ds(代码段)寄存器查找IDT表,得到基址,然后通过基址 + 逻辑地址 = 虚拟地址。

4.根据虚拟地址找到物理地址,核心就是查找页表。

问题2.test.c 退出后,如果马上再运行一次,并再进行地址跟踪,你发现有哪些异同?为什么?

答:首先再运行一次程序,相当于一切都是重来的,变量i重新被赋非0值,所以仍然还是会死循环。 继续进行地址跟踪,根据虚拟地址找到物理地址,发现物理地址和第一次运行时的不一样了,因为在这个进程没有被运行时,内存是会被释放的,所以其他进程是可以利用这个内存的,虽然还是给它这个虚拟地址,但是重新分配内存的时候,物理地址并不一定还是那个地址。

本次实验深入理解了操作系统的段、页式内存管理,段表、页表、逻辑地址、线性地址、物理地址等概念。

最新评论
暂无评论~