日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

[linux-nopage]内存映射虚拟字符设备驱动【P119】

發布時間:2025/1/21 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [linux-nopage]内存映射虚拟字符设备驱动【P119】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

      • 目的:內核空間映射到用戶空間
      • 環境:Ubuntu 20.04 linux內核源碼5.11.0-37-generic(版本自選)
      • 實驗結果
      • 實驗知識點
      • 實驗難點
      • 實驗代碼
        • nopage.c
        • Makefile
        • np_test.c
      • 調試過程
        • make
        • sudo insmod nopage.ko
        • sudo mknod /dev/nopage c 92 0 (這里的92是你前面申請的設備號)
        • gcc np_test.c -o ntest

目的:內核空間映射到用戶空間

一個虛擬字符設備驅動程序,將內核空間映射到用戶空間

  • 找到內核地址對應的物理地址
  • 建立新的用戶表項
  • 環境:Ubuntu 20.04 linux內核源碼5.11.0-37-generic(版本自選)

    實驗結果

  • 這是最終的實驗結果圖,中間出現了很多錯誤結果【錯誤過程在錯誤分析】
  • 實驗知識點

  • 加載內核模塊是什么意思
  • 將自己編寫的驅動程序加載到內核當中,linux強大在一切皆文件,實現高類聚低耦合的特點,模塊封裝
    給linux無限可能的機會

  • 如何加載
  • 實驗難點

  • 沒接觸過linux 編譯,前期知識點
    Makefile 文件的作用

  • 類似腳本,將編譯的大部分內容寫在Makefile文件內(該文件要和編譯的.c文件在同一個目錄下)
    剛開是只有

    這三個文件,其他文件大部分是經過make 編譯產生的

    這是教程的一張圖,解釋大部分內容對應我下面的Makefile 文件內容
  • make 指令的作用

  • make 會進入Makefile 文件;根據Makefile 進行編譯
    根據Makefile文件編譯源代碼、連接、生成目標文件、可執行文件。 簡單理解就是執行Makefile這個腳本;
    • 向內核添加模塊:
  • 編寫驅動程序文件

  • 將驅動文件放置到linux 內核源碼相應的目錄下

  • 在目錄Kconfig 文件中添加新驅動程序對應的項目編譯選擇

  • 在目錄Makefile文件中添加新的驅動程序編譯語句

  • 怎么編譯進內核

  • 根據Makefile 指定的內核地址進入到內核中;

    這是我調試錯誤過程的一種圖,看見執行make先進入指定的內核地址,內核內也有Makefile文件;
    定位到140行:
    中間花費了一點時間在這里調試,后期發現主要bug不在這里;

    主要bug 還是因為沒有安裝gcc
    這里花費時間是因為一開始我檢測系統發現已經有gcc, 后來在編譯文件才發現系統的gcc不能用,前兩個是系統自帶的。才導致我花了大量時間
    最后一個是我后來安裝上的 sudo apt install gcc

  • 遇到錯誤怎么排錯
  • google baidu 教材

  • 課本的指令是什么意思
  • make # 編譯
    insmod xxx.ko # 根據編譯結果會產生.ko文件,此時會執行module_init(xxx)函數

    通過命令 dmesg | tail 最后幾行可以發現 經過insmod 之后進入init函數
    前兩句是插入的模塊未在模塊樹內,也就是外來模塊會提示這一消息,學習過程可以忽略;

    實驗代碼

    nopage.c

    #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/fcntl.h>#include <linux/vmalloc.h> //空間分配到堆 #include <linux/uaccess.h> #include <linux/io.h>#include <asm/page.h> #include <linux/mm.h> //重點學習#define MMAPNOPAGE_DEV_NAME "nopage" //字符設備名稱 #define MMAPNOPAGE_DEV_MAJOR 92 //字符設備號#define SHARE_MEM_PAGE_COUNT 4 //共享頁數 #define SHARE_MEM_SIZE (PAGE_SIZE*SHARE_MEM_PAGE_COUNT)char *share_memory=NULL;vm_fault_t mmapnopage_vm_fault(struct vm_fault *vmf) //這個函數跟之前版本的函數不同,這個形參只有一個,這個要在mm.h下查看才能確定不同版本不同 {struct page *page;unsigned long offset;void *page_ptr;struct vm_area_struct *vma=vmf->vma; //早期版本該變量時形參,現在已經在vm_fault 結構體內定義直接使用printk("\n");printk("%-25s %08x\n","1)vma->flags",vmf->flags);printk("%-25s %08lx\n","2)vmf->pgoff",vmf->pgoff);printk("%-25s %08lx\n","3)vmf->virtual_address",vmf->address); // 虛擬存儲區中斷地址變量為address 更之前也有差別,在mm.h 下可以找到對應 變量為long unsigned int 跟之前的有區別printk("%-25s %08lx\n","4)vma->vm_start",vma->vm_start);printk("%-25s %08lx\n","5)vma->vm_end",vma->vm_end);printk("%-25s %08lx\n","6)vma->vm_pgoff",vma->vm_pgoff);/*printk("%-25s %d\n","7)PAGE_SHIFT",PAGE_SHIFT);*/page_ptr=NULL;if((NULL==vma)||(NULL==share_memory)){printk("return VM_FAULT_SIGBUS!\n");return VM_FAULT_SIGBUS;}offset=vmf->address-vma->vm_start; //偏移量if(offset>=SHARE_MEM_SIZE){printk("return VM_FAULT_SIGBUS!");return VM_FAULT_SIGBUS;}page_ptr=share_memory+offset;page=vmalloc_to_page(page_ptr);get_page(page);vmf->page=page;return 0; }struct vm_operations_struct mmapnopage_vm_ops={.fault=mmapnopage_vm_fault, //中斷 };int mmapnopage_mmap(struct file *filp,struct vm_area_struct *vma) {vma->vm_flags |= VM_NORESERVE; //缺頁映射vma->vm_ops=&mmapnopage_vm_ops;return 0; }struct file_operations mmapnopage_fops={ //文件操作.owner=THIS_MODULE, .mmap=mmapnopage_mmap, };int mmapnopage_init(void) //執行insmod 時進入這個函數 {int lp;int result;result=register_chrdev(MMAPNOPAGE_DEV_MAJOR,MMAPNOPAGE_DEV_NAME,&mmapnopage_fops);if(result<0){printk("regist fails!");return result;}share_memory=vmalloc(SHARE_MEM_SIZE);for(lp=0;lp<SHARE_MEM_PAGE_COUNT;lp++){sprintf(share_memory+PAGE_SIZE*lp,"TEST %d",lp); //向字符設備寫入信息}printk("registing...!");return 0; }void mmapnopage_exit(void) //執行rmmod 時進入該函數 {if(share_memory!=NULL){vfree(share_memory);}unregister_chrdev(MMAPNOPAGE_DEV_MAJOR,MMAPNOPAGE_DEV_NAME); }module_init(mmapnopage_init); module_exit(mmapnopage_exit);MODULE_LICENSE("Dual BSD/GPL");

    Makefile

    下面的Makefile 文件我添加了注釋可能在命令后面多了空格,make會識別錯誤

    ifeq ($(KERNELRELEASE),) //搭配上面的教程使用 CONFIG_MODULE_SIG=n //說是為了避開數字簽名,加了發現也沒用 PWD :=$(shell pwd) //pwd 表示當前工作目錄 present work direction KERSRC := /lib/modules/$(shell uname -r)/build/ //unama -r 指向當前的內核版本modules:$(MAKE) -C $(KERSRC) M=$(PWD) modules // 執行內核模塊的編譯 moules_install:$(MAKE) -C $(KERSRC) M=$(PWD) modules_install // 將模塊安裝到對應的模塊路徑只有modules_install 執行才觸發 .PHONY: modules modules_install clean //wei clean:-rm -rf *.o *.cmd.* *.ko //刪除中間標識文件 else modules-objs :=nopage.o obj-m := nopage.o //將nopage.o 編譯為nopage.koendif

    這個Makefile 和 上面是一樣的;

    ifeq ($(KERNELRELEASE),) CONFIG_MODULE_SIG=n PWD :=$(shell pwd) KERSRC := /lib/modules/$(shell uname -r)/build/modules:$(MAKE) -C $(KERSRC) M=$(PWD) modules moules_install:$(MAKE) -C $(KERSRC) M=$(PWD) modules_install .PHONY: modules modules_install clean clean:-rm -rf *.o *.cmd.* *.ko else modules-objs :=mmapnopage.o obj-m := mmapnopage.oendif

    np_test.c

    #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h>// #define DEVICE_FILENAME "/dev/mmapnopage" #define DEVICE_FILENAME "/dev/nopage"#define SHARE_MEM_PAGE_COUNT 4 #define SHARE_MEM_SIZE (4096*SHARE_MEM_PAGE_COUNT)int main() {int dev;int loop;char *ptrdata;dev=open(DEVICE_FILENAME,O_RDWR|O_NDELAY); //設備打開成功,返回句柄大于0if(dev < 0)printf("can't open nopage\n"); // return < 0 fail! if(dev>=0){printf("open file success!\n");ptrdata=(char*)mmap(0,SHARE_MEM_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,dev,0);for(loop=0;loop<SHARE_MEM_PAGE_COUNT;loop++){printf("[%-10s----%s]\n",ptrdata+4096*loop,ptrdata+4096*loop);}munmap(ptrdata,SHARE_MEM_SIZE);close(dev);}return 0; }

    調試過程

    實驗出現的錯誤:

  • Makefile 文件
    Makefile missing separator. Stop.
  • 這是由于Makefile 文件中的空格鍵個數和tab鍵導致的
    No rule to make target ‘make’, needed by ‘modules’
    解決方法:文本打開直接使用tab 鍵,不要用空格代替,Makefile以空格為命令行的分界,對符號敏感

    進入Makefile文件


    沒有進入ifeq條件
    猜想應該是.config 文件這個變量設置問題
    找到.config 發現沒有找到該變量

    .config 在當前源碼里面下
    針對這個問題查看資料源碼花費了很多時間還是沒能解決
    就進入下一個問題

  • gcc 沒有發現,首先查找有沒有安裝
  • 發現有安裝(最后一個是最后安裝上的)(其實主要原因還是沒有安裝gcc)系統自帶的不能用;

    后面嘗試編譯一個文件gcc hello.c -o test # 這個是我用來測試用的
    發現這個時候找不到gcc
    于是

    sudo apt-get install gcc
    產生這么多錯誤的原因是沒有 sudo apt install gcc;
    在排除上面這個問題的過程中花了很多時間
    現在終于進入到錯誤里面

    上面是環境問題還沒進入到代碼里;

    接下來調試才真正進入調試階段;


    進入到頭文件

    這是mm.h文件下

    兩個錯誤修改地址后
    note: each undeclared identifier is reported only once for each function it appears in

    71行20列定位;

    make

    Make 編譯成功:

    sudo insmod nopage.ko

    insmod: ERROR: could not insert module mmapnopage.ko: Device or resource busy
    這是因為申請的設備號被占用了
    查看當前字符設備號使用情況

    cat /proc/devices

    查看設備號使用情況
    將240改為 90


    重新執行命令

    sudo mknod /dev/nopage c 92 0 (這里的92是你前面申請的設備號)

    92 可以通過命令 grep nopage /proc/devices 返回得到
    參數c 代表的是字符設

    gcc np_test.c -o ntest

    ./ntest
    出現錯誤


    np_test.c源碼

    查看是否加載模塊成功

    黃色代表字符設備

    后來想到是不是權限問題
    我先查看了一下權限
    在/dev 下ll
    先看mmapnopage字符設備對于普通用戶只有讀權限(nopage 是我修改過的,原本和mmapnopage一樣)
    修改為可讀可寫
    chmod 666 nopage #(666 = rw-=4+2+0)

    之后再編譯一下gcc np_test.c -o ntest
    ./ntest

    結束

    總結

    以上是生活随笔為你收集整理的[linux-nopage]内存映射虚拟字符设备驱动【P119】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。