1. Openwrt增加自定义内核模块
- 在package/kernel目录下创建你的内核模块目录test,test下创建src目录存放源码
mkdir -p package/kernel/test
- 在package/kernel/test/目录下创建Makefile并填入以下内容
#
# Copyright (C) 2006-2009 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=test
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/test
SUBMENU:=Other modules
TITLE:=test kernel drive
FILES:=$(PKG_BUILD_DIR)/test.ko
AUTOLOAD:=$(call AutoProbe,81,test)
KCONFIG:=
endef
EXTRA_KCONFIG:= \
CONFIG_TEST=m
EXTRA_CFLAGS:= \
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
MAKE_OPTS:= \
$(KERNEL_MAKE_FLAGS) \
M="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
$(EXTRA_KCONFIG)
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
$(MAKE_OPTS) \
modules
endef
$(eval $(call KernelPackage,test))
- 在package/kernel/test/src/目录下创建test_main.c, 输入以下代码(内核模块从文件读内容):
#include <linux/module.h>
#include <linux/init.h>
static char buf1[20];
int __init hello_init(void)
{
struct file *fp;
loff_t pos;
printk("hello enter/n");
fp =filp_open("/tmp/test_config",O_RDWR,0666);
if (IS_ERR(fp)){
printk("create file error/n");
return -1;
}
pos =0;
kernel_read(fp, buf1, sizeof(buf1), &pos);
printk("#######read: %s\n",buf1);
filp_close(fp, NULL);
return 0;
}
void __exit hello_exit(void)
{
printk("hello exit/n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
- package/kernel/test/src目录下创建kconfig和Makefile
Kconfig内容:
config TEST
tristate "test kernel driver"
help
This is test Driver
if unsure ,delete it ,just for fun
Makefile内容:
test-y := test_main.o
obj-${CONFIG_TEST} = test.o
回到openwrt根目录,使用make menuconfig配置test模块(kernel modules->other modules->test)
编译
make package/test/compile V=99
编译后ko文件在:
./build_dir/target-aarch64_cortex-a53_musl/linux-armvirt_64/mydrvv/test.ko
./staging_dir/target-aarch64_cortex-a53_musl/root-armvirt/lib/modules/5.10.146/test.ko
- 运行
编译好的ko放到qemu模拟的arm板上加载运行
scp ./build_dir/target-aarch64_cortex-a53_musl/linux-armvirt_64/test/test.ko root@192.168.1.1:/tmp/
root@OpenWrt:/tmp#echo sldfjasl > /tmp/test_config
root@OpenWrt:/tmp# insmod test.ko
[88408.502812] hello enter/n
[88408.524385] #######read: sldfjasl
[88408.524385]
root@OpenWrt:/tmp#
PS:
linux4.0版本后取消了vfs_read()的符号导出EXPORT_SYMBOL(vfs_read)
解决办法:
(1)使用fp->f_op->read()函数,但是使用这个,虽然可以编译通过,但是在加载时,fp->f_op->read的返回值是NULL,原因未找到;
(2)使用修改内核(不建议,会污染内核):在vfs_read()函数后添加EXPORT_SYMBOL(vfs_read);导出符号表
(3)(推荐)使用int kernel_read(struct file *file, loff_t offset, char *addr, unsigned long count)函数:
file:文件; offset:读位址; addr:地址指针; count:读的字节数,返回值是成功返回字节数,失败返回负值;
理由:vfs_read()定义:
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
参数中__user 表示buf是用户态指针,在内核中无法使用,因此需要设置使用环境,如下:
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(get_ds());
vfs_read(file, (void __user *)addr, count, &pos);
set_fs(old_fs);
而kernel_read()就是通上述操作进行封装,因此使用kernel_read更便捷,此外,在linux-4.0以后的版本中取消了对vfs_read()的符号导出,因此无法在编译成模块时使用,而kernel_read()有符号导出,可以在编译成模块时使用。
2. Openwrt增加自定义用户态模块
- 在package/目录下创建你的用户态模块目录test-app,test下创建src目录存放源码
mkdir -p package/test-app
- 在package/test-app/目录下创建Makefile并填入以下内容
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME := hw-qos
PKG_VERSION := 0.1
PKG_RELEASE := 1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=xb Package
SUBMENU:=Software Testing modules
TITLE:=This is hw-qos cli.
MAINTAINER:=xiabing
endef
define Package/$(PKG_NAME)/description
If you can't figure out what this program does, you're probably
brain-dead and need immediate medical attention.
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
ARCH="$(LINUX_KARCH)" \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS) -Wall" \
LDFLAGS="$(TARGET_LDFLAGS)"
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/app/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/app/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
- 在package/test-app/src/目录下创建test.c, 输入以下代码:
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char **argv)
{
int i = 0;
printf("hello world \n");
return 0;
}
- 在package/test-app/src/目录下创建Makefile
Makefile内容:
all: hw-qos
hw-qos:
$(CC) $(CFLAGS) -o $@ hw-qos.c -Wall
clean:
rm -f hw-qos
回到openwrt根目录,使用make menuconfig配置test模块(xb package(你在makefile里指定的)->Software Testing modules->test)
编译
make package/test/compile V=99
- 运行
编译好的ko放到qemu模拟的arm板上加载运行
scp ./build_dir/target-aarch64_cortex-a53_musl/test/test root@192.168.1.1:/tmp/
root@OpenWrt:/tmp# chmod 777 test
root@OpenWrt:/tmp# ./test
hello world