Linux操作系统实验4——内存映射

news2024/7/6 20:08:27

实验要求:

1.在源码中查看file_operations和vm_operations_struct结构定义及其操作对象的方法,重点查看mmap方法fault方法的参选类型。

2.设备模块代码的编写和调试,重新编写file_operations结构中的mmap方法,和vm_operations_struct结构中的fault方法。

3.在用户态通过mmap方法完成对映射内存驱动设备的读和写操作访问。

实验原理:

描述在用户态对内存设备访问过程(read和write)中的函数执行过程及功能:

用户态open函数用于打开字符设备,并且调用内核模块中的mapdrv_open函数,完成打印进程号功能。

用户进程在调用mmap函数系统调用之后,系统为其在当前进程的虚拟地址空间中寻址一段连续的空闲地址,这是通过遍历vm_area_struct链表来实现。当找到了合适的这样的一段区间之后,会为其建立一个vm_area_struct结构,完成这些之后,该进程就有了一个专门用于mmap映射的虚拟内存区了。

但是这个区域的虚拟地址都没有对应的物理页框,接着系统会调用内核空间的系统调用函数mapdrv_mmap,也就是需要我们在file operations(f_op)结构体中定义的这个mmap,它将要完成对vm_area_struct结构中的虚拟地址建立其相应的页表项,传入file指针和vm_area_struct结构体指针这两个参数。mapdrv_mmapfile_operations结构体map_vm_ops的地址赋值给vmavm_ops指针。建立页表项具体实现需要调用内核中定义的map_fault函数,它在进程访问到这个映射空间中的虚拟地址时,发现虚拟地址的页表项为空,引起了缺页时才被调用,建立对应页表项

参考代码:

 map_driver.h:

#include <asm/atomic.h>
#include <linux/semaphore.h>
#include <linux/cdev.h>

struct mapdrvo
{
	struct cdev mapdev;
	atomic_t usage;
};

map_driver.c:

#include <linux/kernel.h>  	
#include <linux/module.h>  
#include <linux/fs.h>  
#include <linux/string.h>  
#include <linux/errno.h>  
#include <linux/mm.h>  
#include <linux/vmalloc.h>  
#include <linux/slab.h>  
#include <linux/sched.h>  
#include <asm/io.h>  
#include <linux/mman.h>  

#define MAP_PAGE_COUNT 10  
#define MAPLEN (PAGE_SIZE*MAP_PAGE_COUNT)  
#define MAP_DEV_MAJOR 240
#define MAP_DEV_NAME "mapnopage"

extern struct mm_struct init_mm;  
void map_vopen(struct vm_area_struct *vma);
void map_vclose(struct vm_area_struct *vma);  
/*device mmap */  
static int mapdrv_mmap(struct file *file, struct vm_area_struct *vma);  
static int mapdrv_open(struct inode *inode, struct file *file); 
/* vm area nopage */  
int map_fault(struct vm_fault *vmf);  
  
static struct file_operations mapdrvo_fops = {  
    .owner = THIS_MODULE,  
    .mmap = mapdrv_mmap,  
    .open = mapdrv_open,
}; 

static struct vm_operations_struct map_vm_ops = {
    .open = map_vopen,
    .close = map_vclose,
    .fault = map_fault,
};
   
 
static char *vmalloc_area = NULL;  

MODULE_LICENSE("GPL");  
  
static int __init mapdrv_init(void)  
{  
   int result;
   unsigned long virt_addr;
   int i = 1;
   result=register_chrdev(MAP_DEV_MAJOR,MAP_DEV_NAME,&mapdrvo_fops);
   if(result<0){
	   return result;
   }
   vmalloc_area=vmalloc(MAPLEN);
   virt_addr = (unsigned long)vmalloc_area;
   for(virt_addr = (unsigned long)vmalloc_area; virt_addr < (unsigned long)vmalloc_area + MAPLEN; virt_addr += PAGE_SIZE)
   {
	   SetPageReserved(vmalloc_to_page((void *)virt_addr));   
           sprintf((char *)virt_addr, "test %d",i++);             
   }
   /* printk("vmalloc_area at 0x%lx (phys 0x%lx)\n",(unsigned long)vmalloc_area,(unsigned long)vmalloc_to_pfn((void *)vmalloc_area) << PAGE_SHIFT);  */
   printk("vmalloc area apply complate!");
    return 0;
}  
  
static void __exit mapdrv_exit(void)  
{  
    unsigned long virt_addr;  
    /* unreserve all pages */  
    for(virt_addr = (unsigned long)vmalloc_area; virt_addr < (    unsigned long)vmalloc_area + MAPLEN; virt_addr += PAGE_SIZE) 
    {  
        ClearPageReserved(vmalloc_to_page((void *)virt_addr));  
    }  
    /* and free the two areas */  
    if (vmalloc_area)
        vfree(vmalloc_area);  
    unregister_chrdev(MAP_DEV_MAJOR,MAP_DEV_NAME);
  
}  
  

  
static int mapdrv_mmap(struct file *file, struct vm_area_struct *vma)  
{  
    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;  
    unsigned long size = vma->vm_end - vma->vm_start;  
   
    if (size > MAPLEN) {  
        printk("size too big\n");  
        return -ENXIO;  
    }  
    /*  only support shared mappings. */  
    if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) {  
        printk("writeable mappings must be shared, rejecting\n");  
        return -EINVAL;  
    }  
    /* do not want to have this area swapped out, lock it */  
    vma->vm_flags |= VM_LOCKONFAULT;  
    if (offset == 0) {  
        vma->vm_ops = &map_vm_ops;   
    } else {  
        printk("offset out of range\n");  
        return -ENXIO;  
    }  
    return 0;  
}
static int mapdrv_open(struct inode *inoe, struct file *file)
{

    printk("process: %s (%d)\n", current->comm, current->pid);
    return 0;
}  
  
/* open handler for vm area */  
void map_vopen(struct vm_area_struct *vma)  
{  
    printk("mapping vma is opened..\n");
}  
  
/* close handler form vm area */  
void map_vclose(struct vm_area_struct *vma)  
{  
    printk("mapping vma is closed..\n");
}  
  
/* page fault handler */ 

int map_fault(struct vm_fault *vmf)  
{  
	struct page *page;
	void *page_ptr;
        unsigned long offset, virt_start, pfn_start;	
        offset = vmf->address-vmf->vma->vm_start;
        virt_start = (unsigned long)vmalloc_area + (unsigned long)(vmf->pgoff << PAGE_SHIFT);
        pfn_start = (unsigned long)vmalloc_to_pfn((void *)virt_start);

	printk("\n");    
	/*printk("%-25s %d\n","7)PAGE_SHIFT",PAGE_SHIFT);*/
	page_ptr=NULL;
	if((vmf->vma==NULL)||(vmalloc_area==NULL)){
		printk("return VM_FAULT_SIGBUS!\n");
		return VM_FAULT_SIGBUS;
	}
	if(offset >=MAPLEN){
		printk("return VM_FAULT_SIGBUS!");
		return VM_FAULT_SIGBUS;
	}
	page_ptr=vmalloc_area + offset;
	page=vmalloc_to_page(page_ptr);
	get_page(page);	
	vmf->page=page; 
        printk("%s: map 0x%lx (0x%016lx) to 0x%lx , size: 0x%lx, page:%ld \n", __func__, virt_start, pfn_start << PAGE_SHIFT, vmf->address,PAGE_SIZE,vmf->pgoff);

	return 0;
}

module_init(mapdrv_init);  
module_exit(mapdrv_exit);  

map_driver.c对应Makefile文件:

ifneq ($(KERNELRELEASE),)
	obj-m += map_driver.o
else
	PWD := $(shell pwd)
	KERNELDIR ?= /lib/modules/$(shell uname -r)/build
default:
	$(MAKE) -C $(KERNELDIR)  M=$(PWD) modules
clean:
	@rm -rf *.o *.mod.c *.mod.o *.ko *.order *.symvers .*.cmd .tmp_versions
endif

 maptest_read.c:(读函数)

#include <stdio.h>  
#include <unistd.h>  
#include <sys/mman.h>  
#include <sys/types.h>  
#include <fcntl.h>  
#include <stdlib.h>  
#define LEN (10*4096)  
int main(void)  
{  
    int fd,loop;  
    char *vadr;  
  
    if ((fd = open("/dev/mapnopage", O_RDWR)) < 0) {  
        return 0;  
    }  
    vadr = mmap(0, LEN, PROT_READ, MAP_PRIVATE | MAP_LOCKED, fd, 0);       
    for(loop=0;loop<10;loop++){
        printf("[%-10s----%lx]\n",vadr+4096*loop,vadr+4096*loop);
    }
    while(1)
    {
        sleep(1);
    }
     
}  

maptest_write.c:(写函数)

#include <stdio.h>  
#include <unistd.h>  
#include <sys/mman.h>  
#include <sys/types.h>  
#include <fcntl.h>  
#include <stdlib.h>  
#define LEN (10*4096)  
int main(void) 
{  
    int fd;
    char *vadr;  
  
    if ((fd = open("/dev/mapnopage", O_RDWR)) < 0) {  
        return 0;  
    }  
    vadr = mmap(0, LEN, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, fd, 0);  
    
    sprintf(vadr, "write from userspace");
    
    while(1)
    {
       sleep(1);
    }     
    return 0;
}  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

美团一面:能不能通俗的解释下为什么要有意向锁这个东西?

面试真题&#xff0c;用通俗的例子解释清楚 MySQL 为什么有了表锁和行锁之后&#xff0c;还要引入意向锁 众所周知&#xff0c;InnoDB 中既有读锁也有写锁&#xff0c;也称为共享锁和排他锁&#xff0c;这两种锁既可以加在整张表上&#xff0c;也可以加在行上。 MySQL 自身就提…

【Apifox】设置apiFox自动获取token

文章目录问题描述解决方案注意事项参考文章问题描述 接口测试时&#xff0c;每次都需要手动登录获取token&#xff0c;先登录系统&#xff0c;从浏览器中复制token&#xff0c;再到apifox的接口上把token帖上去&#xff0c;然后才能去测试具体的接口&#xff1b;更麻烦的是&am…

【实时数仓】热度关键词接口、项目整体部署流程

文章目录一 热度关键词接口1 Sugar配置&#xff08;1&#xff09;图表配置&#xff08;2&#xff09;接口地址&#xff08;3&#xff09;数据格式&#xff08;4&#xff09;执行SQL2 数据接口实现&#xff08;1&#xff09;创建关键词统计实体类&#xff08;2&#xff09;Mappe…

小黑hbase终于勉强跑到了自己的m1 Macbook上啦,虽然终端用不了,但是能从happybase访问的日常积累:happybase简单使用

1.happybase连接 # 连接操作 import happybase# 建立连接 con happybase.Connection(localhost, 9090) con.open() # 输出所有表名称 print(con.tables()) # 关闭传输 con.close() con.open()2.创建表格 # 创建表格 con happybase.Connection(localhost, 9090) # 默认9090…

Android 图像混合技术

Android 图像混合技术 色彩知识 色彩 光学三原色 光学三原色由&#xff1a;红、绿、蓝组成。 色值分别是&#xff1a; 红&#xff08;red &#xff09;&#xff1a;#FF0000 RGB&#xff08;255&#xff0c;0&#xff0c;0&#xff09;绿&#xff08;green&#xff09;&am…

第十九讲:神州路由器基础知识

路由器简介路由器&#xff08;Router&#xff09;是连接Internet中多个网络或网段的网络设备&#xff0c;它能将不同网络或网段之间的数据信息进行“翻译”&#xff0c;以使它们能够相互“读”懂对方的数据&#xff0c;实现不同网络或网段的互联互通。此外&#xff0c;它会根据…

数据平台建设指南(上)

前言 年底了&#xff0c;整理了下过去做的一些项目&#xff0c;希望能够给大数据行业的同学提供些大数据平台建设的思路。内容大致分五部分&#xff1a;数据采集&#xff0c;数据存储、数据计算、基础平台以及数据治理篇。由于涉及到的内容较多&#xff0c;打算分成两篇文章&am…

PHY驱动注册部分

SOC可以对PHY 进行配置或者读取PHY 相关状态&#xff0c;这个就需要 PHY 内部寄存器去实现了。PHY 芯片寄存器地址空间为 5位&#xff08;支持访问32个寄存器).IEEE 定义了0~15这 16个寄存器的功能。而 16~31这16 个寄存器由厂商自行实现。 就是说不管你用的哪个厂家的 PHY 芯…

SAP ABAP——SAP简介(三)【S/4 HANA开发环境】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

linux常用命令(三)-目录操作

目录创建 - mkdir 我们可以使用mkdir&#xff08;make directory&#xff09;来创建目录。 示例 目录删除 - rm 可以使用rm&#xff08;remove&#xff09;来删除一个目录 语法 rm [-irf] name ...i&#xff1a;删除前逐一询问确认r&#xff1a;将目录及以下之档案亦逐一删…

转转AB平台的设计与实现

导读 在数据驱动时代&#xff0c;不管是在产品功能迭代还是策略决策时都需要数据的支撑。那么&#xff0c;当我们准备上线一个新功能或者策略时&#xff0c;如何评估新老版本优劣&#xff0c;即数据的可量化就成了问题。这个时候就需要引入 A/B Test 了。 一、A/B Test 是什么…

Tomcat基本用法

Tomcat基本用法一、Tomcat 是什么二、下载安装三、目录结构四、启动服务器五、部署静态页面一、Tomcat 是什么 汤姆猫&#xff1f; 事实上&#xff0c;Java 世界中的 “汤姆猫” 完全不是一回事&#xff0c;但是同样大名鼎鼎 ~ Tomcat 是一个 HTTP 服务器。 前面我们已经学…

公司如何做好舆情监控,舆情监控解决方案有哪些?

随着互联网快速发展&#xff0c;企业网络舆情动态成为决策发展的重要依据&#xff0c;所以做好网络舆情监控至关重要&#xff0c;接下来TOOM舆情监测小编带您简单了解公司如何做好舆情监控&#xff0c;舆情监控解决方案有哪些? 一、公司如何做好舆情监控 舆情监控是指通过不…

Spring Boot 使用 SpringDoc 库的 Swagger3.0

Swagger 定义 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法&#xff0c;参数和模型紧密集成到服务器端的代码&#xff0c;允许API来始终保持同步…

房产管理系统平台安全性分析?

房产管理系统是数图互通公司自主研发的FMCenterV5.0平台&#xff0c;是针对中国高校房产的管理特点和管理要求&#xff0c;研发的一套标准产品&#xff1b;通过在中国100多所高校的成功实施和迭代&#xff0c;形成了一套成熟、完善、全生命周期的房屋资源管理解决方案。 以下是…

FL Studio21电脑版免费音乐编曲宿主软件下载

编曲主要考验电脑的处理器&#xff08;CPU&#xff09;性能、声卡。所以配置电脑的时候有条件的伙伴可以着重考虑这两方面。现在市面上惠普、戴尔、华为、苹果等品牌的电脑&#xff0c;在四五千这个范围的商务本&#xff0c;就可以胜任编曲工作。但是在一些较为庞大的工程中可能…

SolarMesh(微服务监管平台)安装教程

SolarMesh简介 SolarMesh是基于服务网格构建的微服务监管平台。SolarMesh基于 Istio 及容器技术&#xff0c;提供微服务流量监控和管理&#xff0c;提供完善的非侵入式服务治理解决方案&#xff0c;在提供Istio流量管理等基础能力外&#xff0c;还提供多集群纳管、监控告警、W…

为什么全球科技巨头都在布局超高清?

我们能明显地感受到&#xff0c;进入21世纪以来&#xff0c;影像视频所占用人类生活的时间、空间已达到人类诞生以来的最大值。根据《2022全球互联网现象报告》&#xff0c;2021年流媒体视频占互联网带宽流量的53.7%&#xff0c;比2020年提升了4.8%。衣食住行&#xff0c;休闲娱…

十亿人都在用的健康码,运维体系是怎么设计的?

导读&#xff5c;随着疫情防控模式的迭代&#xff0c;健康码访问DAU逐渐趋于下跌&#xff0c;意味着健康码将逐步完成历史使命&#xff0c;见证着疫情的结束。本文特邀腾讯研发工程师李雄政将从技术架构、可观测体系、运营保障体系等运维体系多方面&#xff0c;总结回顾健康码业…

骨传导耳机到底怎么样,五款好用的骨传导耳机推荐

还有很多人不知道骨传导耳机使用感受到底如何&#xff0c;骨传导耳机是开放式的听音方式&#xff0c;在使用骨传导耳机时&#xff0c;会更加安全、耳机的声音相对于入耳式的声音会更加具有空间立体感&#xff0c;具体使用感感受到底如何&#xff0c;看下文大家就有一定的了解了…