【Openwrt】增加自定义模块

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 
#include 

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 [email protected]:/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 
#include 
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  [email protected]:/tmp/

root@OpenWrt:/tmp# chmod 777 test
root@OpenWrt:/tmp# ./test
hello world

你可能感兴趣的:(【Openwrt】增加自定义模块)