【nachos】山东大学操作系统课设实验nachos系统(5)扩展地址空间

实验目的:

尝试在nachos下扩展内存空间的实现,使其能够支持多程序并行执行
尝试实现系统调用Exec() 和 Exit()

一、对现有内存空间的分析。

现有的内存空间(对页表的封装)是由AddrSpace类的对象实现的。
每当一个用户程序启动时,内核要创建一个AddrSpace对象。AddrSpace对象在初始化时负责读取可执行文件的内容,为其分配内存(以页表的形式),并给出其逻辑地址(VirtualAddr)到物理地址(PhysicalAddr)的映射。之后,Addrspace还会负责将可执行文件的内容读取到内存(这里指虚拟机内存,mechine->mainMemory)中。
每一个Thread线程对象维护一个页表,在Thread被调用时,会调用其内部AddrSpace对象的Restore方法,在这个方法中,将nachos虚拟机的当前页表设为线程维护的页表。

但是,现有的AddrSpace中初始化方法非常简单,基本是只在考虑单用户程序执行的情况,在分配逻辑页表到物理页表的对应关系时,仅仅是简单的一一对应,在将可执行文件读入内存时,也是一样的情况。这样就会导致,在多道执行用户程序时,后创建的用户程序会覆盖之前的程序,还会引起很多严重的问题。

二、对现有内存空间的扩展

上个实验中,我们为AddrSpace类添加了方法Print()用于查看内存页表的分配情况以及对应关系。
本次实验依旧在AddrSpace构造方法最末尾添加Print()(若已有则保留),便于调试。

除此之外,我们共须修改AddrSpace三处实现。

1.逻辑页表与物理页表对应关系

首先,打开AddrSpace.cc找到构造方法中注释:“first, set up the translation”

这里写图片描述

可以看到,这里的分配仅仅是两边都从零开始逐页分配,这样并不能满足需求。
考虑在文件系统中,使用了BitMap来对磁盘中的空闲扇区进行管理和检索,在分配空闲页时,我们可以类比磁盘中的空闲扇区分配。这就需要AddrSpace类维护一个静态的BitMap来标注物理内存中的页表分配情况。
打开AddrSpace.h,添加#include “bitmap.h”来导入bitmap类。
在AddrSpace类的定义中,在private块中加入声明

static BitMap *bitmap;

这里写图片描述

回到AddrSpace.cc,在构造方法前,创建静态对象bitmap

BitMap* AddrSpace::bitmap = new BitMap(NumPhysPages);

这里写图片描述

至此,我们在AddrSpace类中创建了BitMap对象,用于管理空闲内存页表。

应用到物理内存页表的分配时,只需要将

pageTable[i].physicalPage=i;
替换为
pageTable[i].physicalPage=bitmap->Find();

即可。

这里写图片描述
另外,我们需要在析构函数中将这个空间释放,保证在内存空间删除时,能够及时地将空间释放出来。

这里写图片描述

2.修改可执行文件读取到内存的逻辑

在addrspace.cc中搜索注释// then,
可以看到以下代码,负责将可执行文件的内容读取到内存中。

这里写图片描述

但是,可以看到在将文件读取到内存的实现中,仅仅将逻辑地址作为物理地址进行读入,这样逻辑地址和物理地址的对应关系就失去了意义。
要做修改,就要将code.virtualAddr和initData.virtualAddr转换为与上面物理页表的对应的物理地址。
经过操作系统课程的学习,我们可以知道,逻辑地址转换为物理地址,是由逻辑地址所属物理页表的头地址,加上该逻辑地址在该页表中的偏移量得出的。
将这个实际地址与现在的逻辑地址替换,得到

这里写图片描述

    if (noffH.code.size > 0) {
        DEBUG('a', "Initializing code segment, at 0x%x, size %d\n", 
            noffH.code.virtualAddr, noffH.code.size);

    //code start from this page
    int code_page = noffH.code.virtualAddr/PageSize;
    //calculate physical address using page and offset (0);
    int code_phy_addr = pageTable[code_page].physicalPage *PageSize;
    //read memory
        executable->ReadAt(&(machine->mainMemory[code_phy_addr]),
            noffH.code.size, noffH.code.inFileAddr);
    }
    if (noffH.initData.size > 0) {
        DEBUG('a', "Initializing data segment, at 0x%x, size %d\n", 
            noffH.initData.virtualAddr, noffH.initData.size);
    //data start from this page
    int data_page = noffH.initData.virtualAddr/PageSize;
    //first data's offset of this page
    int data_offset = noffH.initData.virtualAddr%PageSize;
    //calculate physical address using page and offset ;
    int data_phy_addr = pageTable[data_page].physicalPage *PageSize + data_offset;  
    //read memory
        executable->ReadAt(&(machine->mainMemory[data_phy_addr]),
            noffH.initData.size, noffH.initData.inFileAddr);
    }

3.对初始化内存的修改

在构造函数中可以找到一条语句:

bzero(machine->mainMemory, size);

这是在创建AddrSpace对象时,清空整个内存的操作。但是,我们如果创建了新的AddrSpace,就会把原有的内存全部清空。而实际上,在将新的可执行文件读入内存时,不需要清空内存也可以正常执行,所以我们简单地注释掉这一行。

这里写图片描述

至此,扩展内存空间的工作完成。

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值