差異處
這裏顯示兩個版本的差異處。
Both sides previous revision 前次修改 下次修改 | 前次修改 | ||
cpp:linux_kernel:show_physical_address [2017/09/30 18:20] tony [Introduction] |
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]] | ||
+ | * [[http://blog.csdn.net/freenaut/article/details/4298174|字符设备 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()]] | ||
+ | ===== ===== | ||
+ | ---- | ||
+ | \\ | ||
+ | ~~DISQUS~~ |