zoukankan      html  css  js  c++  java
  • 操作系统实验06-地址映射与共享

    实验内容

    • 1.在保护模式下(启动了分段和分页机制以后)工作的Linux 0.11代码中加上一个内存寻址指令,并且在该内存地址处放置一个自己构造的数据,应用Bochs调试工具跟踪该地址的从逻辑地址、GDT表、线性地址、页表、物理地址的过程,最后验证是否是自己放置的数据?实际上就是手动进行一次地址翻译工作。
      1. 实现两个进程通过页共享来进行相互通信。

    步骤

    1.创建test.c

    挂载hdc文件系统,然后在usr/root目录内增加test.c文件用于测试地址映射,代码如下:

    #include <stdio.h>
    
    int i = 0x12345678;
    
    int main(void)
    {
        printf("The logical/virtual address of i is 0x%08x", &i);
        fflush(stdout);
    
        while (i)
            ;
    
        return 0;
    }
    

    代码添加过程截图如下:

    2.寻找物理地址

    首先进入Linux-0.11目录内make编译系统,然后回退至oslab目录内运行系统,再使用下述命令编译运行test.c文件

    gcc -o test test.c
    ./test
    

    运行效果如下图所示:

    此时会进入在test.c内的while死循环,然后ctrl+c暂停bochs。
    此时需要让Linux-0.11的test跳出死循环,所以需要找到逻辑地址ds:0X00003004对应的物理地址,将它的内容更改为0。
    在终端中输入sreg,得到gdtr的基址值为0x00005cb8,ldtr为0x0068即0000 0000 0110 1000 b,可知索引为1101b即13,TI位为0,即GDT中的第13项为LDT的段描述符。

    输入xp /2w 0x00005cb8+138得到LDT段描述符,可以得到LDT的基址为0x00f9a2d0
    ds段选择子为0x0017 => 0000 0000 0001 0111 b,可知索引为10b即2,TI位为1,即LDT中的第2项为ds的段描述符,输入xp/2w 0x00f9a2d0+2
    8得到ds段描述符,可以知道ds的基址为0x10000000,所以0x3004对应的线性地址为0x10000000+0x3004=0x10003004。输入xp /w 644获取页目录项,可知页表基地址为0x00fa6000。
    输入xp /w 0x00fa6000+3
    4得到物理基址为0xfa5000。
    输入xp /w 0xfa5000+4得到的内容即test.c中的变量的值,输入setpmem 0xfa5004 4 0将它设为0。

    然后在终端内输入c继续让系统运行,发现test而已跳出循环。

    3.添加系统调用

    在unistd.h中增加下面的代码:

    #define SHM_SIZE 64
     
    typedef struct shm_ds
    {
        unsigned int key;
        unsigned int size;
        unsigned long page;
    }shm_ds;
    
    int sys_shmget(unsigned int key,size_t size);
    void * sys_shmat(int shmid);
    

    然后增加两个系统调用

    #define __NR_shmget 76
    #define __NR_shmat 77
    

    4.修改sys.h文件

    在此文件中增加函数声明:

    extern int sys_shmget();
    extern int sys_shmat();
    

    在system_call.s中把nr_system_calls改为78

    5.增加shm.c

    shm.c的位置在kernel目录下
    代码如下:

    #define __LIBRARY__
    #include <unistd.h>
    #include <linux/kernel.h>
    #include <linux/sched.h>
    #include <linux/mm.h>
    #include <errno.h>
    
    static shm_ds shm_list[SHM_SIZE] = {{0,0,0}};
    
    int sys_shmget(unsigned int key, size_t size)
    {
        int i;
        void *page;
        if(size > PAGE_SIZE)
            return -EINVAL;
        page = get_free_page();
        if(!page)
            return -ENOMEM;
        printk("shmget get memory's address is 0x%08x
    ",page);
        for(i=0; i<SHM_SIZE; i++)
        {
            if(shm_list[i].key == key)
                return i;
        }
        for(i=0; i<SHM_SIZE; i++)
        {
            if(shm_list[i].key == 0)
            {
                   shm_list[i].page = page;
                shm_list[i].key = key;
                shm_list[i].size = size;
                return i;
            }
        }
        return -1;
    }
    
    void * sys_shmat(int shmid)
    {
        int i;
        unsigned long data_base, brk;
    
        if(shmid < 0 || SHM_SIZE <= shmid || shm_list[shmid].page==0 || shm_list[shmid].key <= 0)
            return (void *)-EINVAL;
    
        data_base = get_base(current->ldt[2]);
        printk("current's data_base = 0x%08x,new page = 0x%08x
    ",data_base,shm_list[shmid].page);
    
        brk = current->brk + data_base;
        current->brk += PAGE_SIZE;
    
        if(put_page(shm_list[shmid].page, brk) == 0)
            return (void *)-ENOMEM;
    
        return (void *)(current->brk - PAGE_SIZE);
    }
    

    然后修改Kernel下的Makefile文件

    ### Dependencies:
    sem.s sem.o: sem.c ../include/linux/sem.h ../include/linux/kernel.h 
    ../include/unistd.h
    shm.s shm.o:shm.c ../include/unistd.h ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/mm.h ../include/errno.h
    ...
    

    修改截图如下:

    6.编写消费者和生产者程序

    在hdc的root目录下增加producer.c和consumer.c文件,这两个文件的代码如下:

    /*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;    
    }
    

    consumer.c代码如下

    /*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!
    ");    
    
        if((p = (int * )shmat(shm_id)) < 0)
            printf("link error!
    ");
        while(1)
        {
            sem_wait(Full);
            sem_wait(Mutex);
    
            printf("pid %d:	consumer consumes item %d
    ", 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;    
    }
    

    7.运行验证

    运行bochs,输入:

    gcc -o pro producer.c
    gcc -o con consumer.c
    

    编译这两个程序,
    然后输入

    pro > proOutput &
    con > conOutput &
    

    来同时运行这两个程序,并将结果保存到proOutput和conOutput中。
    最后输入sync,结果如下

    关闭linux-0.11回到ubunt终端,输入sudo less hdc/usr/root/conOutput查看结果如下:

  • 相关阅读:
    0:一种过滤机制的MobileMenuList
    MobileMenuImage
    (转)How To Kill runaway processes After Terminating Concurrent Request
    fnd_profile.value('AFLOG_ENABLED')的取值 和配置文件相关SQL
    供应商 银行 SQL (转自ITPUB)
    重启并发管理器
    定义并发请求时 业务实体值集显示没有值数据
    Oracle EBS环境下查找数据源(OAF篇)
    查看在线EBS用户的相关信息
    转,Oracle中关于处理小数点位数的几个函数,取小数位数,Oracle查询函数
  • 原文地址:https://www.cnblogs.com/mirage-mc/p/13034973.html
Copyright © 2011-2022 走看看