我试图在Linux内核模块中获取电池电量(模块通过modprobe插入).理想情况下,我希望使用内核API调用来获取电池信息.我在网上搜索了解决方案,我还探索了Linux内核源代码和Michael Meskes的程序源代码"acpi"的想法.
这些是我认为我可以使用的一些技术:
/proc/acpi/battery/BAT0/state和/proc/acpi/battery/BAT0/info/sys/class/power_supply/BAT0/charge_now并且charge_full不涉及解析.acpi_battery_get_status和acpi_battery_get_infoacpi_battery_read,就在它上面有一个评论说"Driver Interface".如果有人知道如何使用它,这可能是另一种方式.我认为在内核模块中读取文件可能是一个坏主意,但我不确定这些文件如何映射到内核函数调用,所以它可能没问题.
那么,你们能给我一些建议/建议吗?
编辑:我在下面的答案中包含了我的解决方案.
我正在进行内核工作以进行一些夏季研究.我们希望在特定的RTT计算中对TCP进行修改.我想要做的是将tcp_input.c中某个函数的分辨率替换为动态加载的内核模块提供的函数.我认为这将提高我们开发和分发修改的速度.
我感兴趣的函数被声明为static,但我已经使用非静态函数重新编译内核并由EXPORT_SYMBOL导出.这意味着该功能现在可供内核的其他模块/部分访问.我通过"cat/proc/kallsyms"验证了这一点.
现在我希望能够加载一个可以重写符号地址的模块,从初始到动态加载的函数.同样,当要卸载模块时,它将恢复原始地址.这是一种可行的方法吗?你们都有建议如何更好地实施这项建议吗?
谢谢!
编辑:
这是我的最终方法.
给定以下函数(我想要覆盖,并且不导出):
static void internal_function(void)
{
// do something interesting
return;
}
Run Code Online (Sandbox Code Playgroud)
像这样修改:
static void internal_function_original(void)
{
// do something interesting
return;
}
static void (*internal_function)(void) = &internal_function_original;
EXPORT_SYMBOL(internal_function);
Run Code Online (Sandbox Code Playgroud)
这将重新定义了预期的函数标识符,而不是指向原始实现的函数指针(可以以类似的方式调用).EXPORT_SYMBOL()使地址可以全局访问,因此我们可以从模块(或其他内核位置)修改它.
现在您可以使用以下格式编写内核模块:
static void (*original_function_reference)(void);
extern void (*internal_function)(void);
static void new_function_implementation(void)
{
// do something new and interesting
// return
}
int init_module(void)
{
original_function_reference = internal_function;
internal_function = &new_function_implementation;
return 0;
}
void cleanup_module(void)
{
internal_function = original_function_reference;
}
Run Code Online (Sandbox Code Playgroud)
此模块使用动态加载的版本替换原始实现.卸载后,将恢复原始引用(和实现).在我的具体案例中,我为TCP中的RTT提供了一个新的估算器.通过使用模块,我可以进行小的调整并重新开始测试,所有这些都无需重新编译和重新启动内核.
我有兴趣分析Linux内核的模块.我这样试过:
CONFIG_PROFILING=yprofile=2echo 123 > /proc/profileioctl调用使用模块的用户空间应用程序.测试应用程序按预期工作,因此模块工作正常.readprofile -p /proc/profile -m System.map位置读取分析信息.到现在为止还挺好.几乎一切都按预期工作.什么也没有但是工作是,我没有得到我的模块任何信息,即没有从模块的任何功能的提及.
然而,在第二个想法,我记得我忘了重新编译模块使用CONFIG_PROFILING=y.
所以,我的问题是:模块是否没有出现在分析日志中,因为它没有编译过,CONFIG_PROFILING=y或者是否还有一些我不知道的更明显的原因?
如果有人想知道,为什么我要求而不是直接尝试,那是因为,我不能在家里做,而且我更愿意在再次访问代码之前听到知识渊博的话.
从源代码构建Linux内核时,可以决定某个函数是静态构建到内核中还是打包到模块中以便通过.config进行动态插入.
另一方面,如果我有任何第三方模块的源代码,例如打包的设备驱动程序,是否可以以静态方式将此代码以编程方式集成到内核中?
我正在尝试创建一个简单的内核模块.我正在尝试将消息打印到dmesg,但我一直在努力
insmod:init_module'hello.ko'在android中失败(Exec格式错误)
之后:dmesg:未知搬迁:27
#include <linux/module.h>
#include <linux/kdb.h>
int init_module(void)
{
printk(KERN_ALERT "Hello world!\n");
return 1;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
MODULE_AUTHOR("Robert P. J. Day");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("2:1.0") ;
MODULE_DESCRIPTION("You have to start somewhere.");
Run Code Online (Sandbox Code Playgroud)
make文件
obj-m +=hello.o
KERNELDIR ?= ~/android/kernel/common
#KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
CROSS_COMPILE=~/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-
ARCH=arm
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
rm *.symvers
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么?以及如何使它工作?
我在做了一个readelf之后发现,当它被编译时,重定位部分指向了错误的方向.
Offset Info Type Sym.Value Sym. Name
00000008 0000171b …Run Code Online (Sandbox Code Playgroud) 我在内核编程新手和我要运行这个内核模块(贴在下面)......我跑了生成文件(贴在下面),但我收到以下错误:可有人请帮助我了解如何克服这一点:内核程序应该没有错误运行,因为它来自英特尔的实现:
obj-m += hello-1.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run Code Online (Sandbox Code Playgroud)
这是错误:
snehil@ubuntu:~/Desktop/measure$ make
make -C /lib/modules/3.0.0-12-generic/build M=/home/snehil/Desktop/measure modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-12-generic'
CC [M] /home/snehil/Desktop/measure/measure1.o
/home/snehil/Desktop/measure/measure1.c: In function ‘hello_start’:
/home/snehil/Desktop/measure/measure1.c:108:2: error: implicit declaration of function
‘kmalloc’ [-Werror=implicit-function-declaration]
/home/snehil/Desktop/measure/measure1.c:108:8: warning: assignment makes pointer from
integer without a cast [enabled by default]
/home/snehil/Desktop/measure/measure1.c:115:11: warning: assignment makes pointer from
integer without a cast [enabled by default]
/home/snehil/Desktop/measure/measure1.c:124:12: warning: assignment makes pointer …Run Code Online (Sandbox Code Playgroud) 我最近在linux源代码树中运行了scripts/checkpatch.pl脚本并得到了这个警告:
WARNING: Prefer netdev_dbg(netdev, ... then dev_dbg(dev, ... then pr_debug(... to printk(KERN_DEBUG ...
printk(KERN_DEBUG "Hello World! \n");
Run Code Online (Sandbox Code Playgroud)
据我所知,pr_debug和dev_dbg提供的动态调试界面对printk有明显的优势,因此它们比printk更受欢迎.
即使在dev_dbg和pr_debug中,如果我们有一个结构设备来标准化设备信息输出以及我们的调试消息,我们更喜欢dev_dbg.它提供了从"编辑/重建/重启循环"中逃脱的功能,还允许通过dynamic_debug/control接口维护整洁的日志.
我的问题是: 为什么netdev_dbg更喜欢dev_dbg?
我想为文件写一个物理内存.内存本身不会再被触摸,因此我想O_DIRECT用来获得最佳的写入性能.
我的第一个想法是打开/dev/mem并映射内存并将所有内容写入一个打开的文件O_DIRECT.写调用EFAULT在mmap返回的内存地址上失败().如果我不使用O_DIRECT,它会产生一个memcpy.
#include <cstdint>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <sys/mman.h>
#define PRINT_ERRNO_REASON(reason) \
case reason: { std::cout << #reason << std::endl; } break;
void write_page_aligned_buffer(int out_fd)
{
const ssize_t PAGE_SIZE = getpagesize();
void* page_aligned_buffer = memalign(PAGE_SIZE, PAGE_SIZE);
if(!page_aligned_buffer)
{
std::cout << "Could not allocate page aligned buffer." << std::endl;
return;
}
std::cout << "Allocated a buffer …Run Code Online (Sandbox Code Playgroud) 我正在尝试编译"hello world"内核模块的示例,在ubuntu 11.04,内核3.2.6,gcc 4.5.2和fedora 16,内核3.2.7,gcc 4.6.7上发现问题.
码:
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
static int __init hello_init (void)
{
printk("Hello module init\n");
return 0;
}
static void __exit hello_exit (void)
{
printk("Hello module exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
Run Code Online (Sandbox Code Playgroud)
编译:
gcc -D__KERNEL__ -I /usr/src/linux/include/ -DMODULE -Wall -O2 -c hello.c -o hello.o
Run Code Online (Sandbox Code Playgroud)
错误:
在/usr/src/linux/include/linux/kernel.h:13:0中的文件中,来自/usr/src/linux/include/linux/cache.h:4,来自/ usr/src/linux/include /linux/time.h:7,来自/usr/src/linux/include/linux/stat.h:60,来自/usr/src/linux/include/linux/module.h:10,来自hello.c: 1:/usr/src/linux/include/linux/linkage.h:5:25:致命错误:asm/linkage.h:找不到文件
然后我发现在/ usr/src/linux/include /中没有名为'asm'但'asm-generic'的文件夹; 所以我把'asm'软链接到'asm-generic',并编译了agail:
这次错误是:
在/usr/src/linux/include/linux/preempt.h:9:0中包含的文件中,来自/usr/src/linux/include/linux/spinlock.h:50,来自/ usr/src/linux/include /linux/seqlock.h:29,来自/usr/src/linux/include/linux/time.h:8,来自/usr/src/linux/include/linux/stat.h:60,来自/ usr/src /linux/include/linux/module.h:10,来自hello.c:1:/usr/src/linux/include/linux/thread_info.h:53:29:致命错误:asm/thread_info.h:文件没有发现
所以我意识到我错了,但为什么呢?T_T
我编写了一些Linux内核代码,它会导致运行时错误和报告linux unable to handle kernel paging request at ffffffff00000010.
它只是open在Linux内核编程中挂钩系统调用的代码.
代码如下:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/fcntl.h>
#include <asm/unistd.h>
#include <asm/ia32_unistd.h>
#include <asm/msr.h>
unsigned long *sys_table = NULL;
asmlinkage long (*old_open) (const char __user *filename, int flags, umode_t mode);
static void *memmem(const void *haystack, size_t haystack_len,
const void *needle, size_t needle_len);
#define dbg(format,args...) \
printk("intercept: function:%s-L%d: "format, __FUNCTION__, __LINE__, ##args);
asmlinkage long new_open(char *filename, int flags, int mode)
{
printk("call open()\n");
return …Run Code Online (Sandbox Code Playgroud)