差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

Both sides previous revision 前次修改
下次修改
前次修改
cpp:linux_kernel:show_physical_address [2017/10/02 00:16]
tony [Reference]
cpp:linux_kernel:show_physical_address [2023/06/25 09:48] (目前版本)
行 1: 行 1:
 +{{tag>​Linux Linux-kernel}}
 ====== Show Physical Memory Address of the kernel module ====== ====== Show Physical Memory Address of the kernel module ======
 ===== Introduction ===== ===== Introduction =====
-我希望透過寫一個kernel module,做以下事情:​ +我希望透過寫一個kernel module,讓user在user space去顯示kernel space某個變數的實體記憶體位置與數值。 
-  - 宣告一global variable。 +\\ 
-  - init時,初始此variable。 +\\ 
-  - 執行file_operations:​ open時,會打印出此變數的實體記憶體位置。 +Note: 由於這程式僅用於測試不會特別去考慮更好的寫法;會補充這點是由於看書有看到更好的寫法
-  - exit時釋放variable+
 ===== How to? ===== ===== How to? =====
 +==== Source Code ====
 +包含以下內容:​
 +  - 在init時,我建立一個字元裝置用以接受user space的操作,並初始hello_buf。
 +  - 當使用者執行cat /​dev/​hello時,會觸發file_operations的open與release,這裡我只實做open的對應行為:​ dump_physical_address。
 +  - dump_physical_address則是取得hello_buf的實體記憶體位置並dump出來。
 +  - exit就是釋放所有用到的資源。
 +<code cpp>
 +#include <​linux/​init.h>​
 +#include <​linux/​module.h>​
 +#include <​linux/​slab.h>​
 +#include <​linux/​string.h>​
 +#include <​asm/​io.h>​
 +#include <​linux/​fs.h>​
  
 +MODULE_LICENSE("​Dual BSD/​GPL"​);​
 +
 +static char* hello_buf;
 +
 +static int dump_physical_address(struct file *filp, struct vm_area_struct *vma)
 +{
 + unsigned long virt_addr;
 + phys_addr_t phy_addr;
 + printk("​damn\n"​);​
 + virt_addr = (unsigned long)hello_buf;​
 + printk("​Hello kernel: %lx, value: %c\n", virt_addr, hello_buf[0]);​
 + phy_addr = virt_to_phys((void*)virt_addr);​
 + printk("​PA:​ 0x%lx\n",​ phy_addr);
 + pr_info("​PA:​ %pa for VA: 0x%lx\n",​ &​phy_addr,​ virt_addr);
 + return 0;
 +}
 +
 +static struct file_operations hello_fops = {
 + open: dump_physical_address,​
 +}; 
 +
 +static int hello_init(void)
 +{
 +
 + int ret = register_chrdev(187,​ "​hello",​ &​hello_fops);​
 + if(ret<​0) {
 + printk("​Unsable to register char device %d\n", ret);
 + return ret;
 + }
 +
 + hello_buf = kmalloc(256,​ GFP_KERNEL);​
 + memset(hello_buf,'​*',​256);​
 + printk("​Hello kernel: %c\n", hello_buf[0]);​
 + return 0;
 +}
 +static void hello_exit(void)
 +{
 + if(hello_buf) {
 +   printk("​Goodbyte kernel: %c\n", hello_buf[0]);​
 +   kfree(hello_buf);​
 + }
 + unregister_chrdev(187,"​hello"​);​
 + printk(KERN_INFO "​Goodbye\n"​);​
 +}
 +
 +module_init(hello_init);​
 +module_exit(hello_exit);​
 +</​code>​
 +==== Makefile ====
 +<​code>​
 +#
 +## Makefile for kernel test
 +#
 +#PWD         := $(shell pwd) 
 +KVERSION ​   := $(shell uname -r)
 +KERNEL_DIR ​  = /​usr/​src/​kernels/​$(KVERSION)/​
 +MODULE_NAME ​ = hello
 +obj-m       := $(MODULE_NAME).o ​  
 +all:
 + make -C $(KERNEL_DIR) M=$(PWD) modules
 +clean:
 + make -C $(KERNEL_DIR) M=$(PWD) clean
 +</​code>​
 +起初我是在centos 7.3上寫,安裝了7.4的kernel header;編譯正常,但載入模組時,會出現Unkown symbol page offset base。最後裝7.3的kernel header就可以正常載入。
 +==== Test Script ====
 +請記得先執行mknod /dev/hello c 187 0去建立裝置檔案,接著就可以透過cat去操作,然後使用demsg看到結果:​
 +<code bash>
 +#!/bin/bash
 +
 +#mknod /dev/hello c 187 0
 +
 +rmmod hello
 +insmod hello.ko
 +cat /dev/hello
 +dmesg | tail
 +</​code>​
 ===== Reference ===== ===== Reference =====
   * [[https://​wwssllabcd.github.io/​blog/​2012/​11/​13/​how-to-make-linux-module/​|一個簡單的 Linux Kernel Module]]   * [[https://​wwssllabcd.github.io/​blog/​2012/​11/​13/​how-to-make-linux-module/​|一個簡單的 Linux Kernel Module]]
   * [[https://​github.com/​torvalds/​linux/​blob/​master/​lib/​test_debug_virtual.c|virt_to_phys sample]]   * [[https://​github.com/​torvalds/​linux/​blob/​master/​lib/​test_debug_virtual.c|virt_to_phys sample]]
 +  * [[http://​blog.csdn.net/​freenaut/​article/​details/​4298174|字符设备 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()]]
  
 +=====    ===== 
 +---- 
 +\\ 
 +~~DISQUS~~