King3399(ubuntu文件系统)驱动模块编译简明教程

该文章仅供参考,编写人不对任何实验设备、人员及测量结果负责!!!

0 引言

文章主要介绍King3399(ubuntu文件系统)驱动模块编译过程,涉及交叉编译工具以及驱动模块的加载与卸载

1 交叉编译工具链

本文驱动开发的编译方式为交叉编译,首先需要知道文件的编译设备与运行设备分别是何种架构,在ubuntu主机与king3399从机的终端分别输入arch查询得到x86_64aarch64,这也就意味着是用x86_64的设备去编译文件,用aarch64的设备去执行文件

其次我们还需要知道king3399内核源码的版本,在king3399从机终端输入uname -a查询得到Linux ubuntu2004 5.10.198 ...aarch64...,从返回结果可以知道版本号为5.10.198,进入king3399从机的/lib/modules目录,可以看到几个以版本号命名的文件夹(在查找资料时看到有人说这里可能没有对应的版本号文件夹,可以尝试创建一个),本人该目录下存在5.10.160与5.10.198这两个文件夹,显然后者为我们的目标文件夹,后边编译好的.ko文件需要放到该文件夹才能够运行

再下一步便是安装交叉编译工具链,由于使用的是官方的SDK进行编译,这个SDK中自带了所需的工具链,因此无需单独安装,关于交叉编译器的使用可以到官方的下述目录去查找:

cdrom_king3399_new\02-软件文档\荣品文档\编译问题\linux\交叉编译器使用说明.pdf

不过这个文件也没有提供什么有用的信息,可能是官方觉得大家都懂,无需多言

至此还有最后一步:找到交叉编译工具的路径,这个在编写Makefile时需要传入交叉编译工具的路径,通常这个工具链会在/home/username/ws/sdk/或者/home/username/ws/sdk/kernel/目录下的脚本中提到,为节约时间这里直接给出涉及到的文件/home/username/ws/sdk/build.sh,可以看到文件中有如下函数:

get_toolchain()
{
	MODULE="$1"
	TC_ARCH="${2/arm64/aarch64}"
	TC_VENDOR="${3-none}"
	TC_OS="${4:-linux}"

	MACHINE=$(uname -m)
	if [ "$MACHINE" != x86_64 ]; then
		notice "Using Non-x86 toolchain for $MODULE!" >&2

		if [ "$TC_ARCH" = aarch64 -a "$MACHINE" != aarch64 ]; then
			echo aarch64-linux-gnu-
		elif [ "$TC_ARCH" = arm -a "$MACHINE" != armv7l ]; then
			echo arm-linux-gnueabihf-
		fi
		return 0
	fi

	# RV1126 uses custom toolchain
	if [ "$RK_CHIP_FAMILY" = "rv1126_rv1109" ]; then
		TC_VENDOR=rockchip
	fi

	TC_DIR="$RK_SDK_DIR/prebuilts/gcc/linux-x86/$TC_ARCH"
	if [ "$TC_VENDOR" ]; then
		TC_PATTERN="$TC_ARCH-$TC_VENDOR-$TC_OS-[^-]*-gcc"
	else
		TC_PATTERN="$TC_ARCH-$TC_OS-[^-]*-gcc"
	fi
	GCC="$(find "$TC_DIR" -name "*gcc" | grep -m 1 "/$TC_PATTERN$" || true)"
	if [ ! -x "$GCC" ]; then
		{
			error "No prebuilt GCC toolchain for $MODULE!"
			error "Arch: $TC_ARCH"
			error "Vendor: $TC_VENDOR"
			error "OS: $TC_OS"
		} >&2
		exit 1
	fi

	echo ${GCC%gcc}
}                     

这是一个shell脚本,本人不精通,不过可以猜出大致内容,有能力的可以尝试翻译翻译,这里取个巧,直接看函数的最后一句echo ${GCC%gcc}这里应该是将传入的ARCH与CROSS_COMPILE合成路径并打印出,有了最终的路径就好办,那再想想我们何时用过这个build.sh文件,编译SDK源码时应该用过,而编译日志里边对编译过程有详细记录,编译日志路径为/home/username/ws/sdk/output/sessions/,进入该路径可以看到若干以时间命令的文件夹,进入一个之前成功编译后的日志,打开xx-all-build.log可以看到有如下内容:

......
^[[36m==========================================^[[0m
^[[36m          Start building all images^[[0m
^[[36m==========================================^[[0m
^[[35mGenerated blank misc image^[[0m
^[[35mDone packing /home/username/ws/sdk/output/firmware/misc.img^[[0m
^[[35mRunning mk-misc.sh - build_misc succeeded.^[[0m
^[[36mToolchain for loader (U-Boot):^[[0m
^[[36m/home/username/ws/sdk/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-^[[0m

^[[36m==========================================^[[0m
^[[36m          Start building loader^[[0m
^[[36m==========================================^[[0m
......

找到关键字串Toolchain,该字串后边所跟便是交叉编译工具链的绝对路径,将该路径复制,后边会用到

至此,一切工作准备就绪,接下来将进行驱动模块的开发

2 驱动模块开发浅尝

驱动模块内容繁多,涉及面极广,本文只以最简单的驱动模块举例,梳理使用king3399进行驱动开发的流程

首先在ubuntu主机/home/username/ws/目录下创建mydriver文件夹,并在该文件夹内创建helloworld.c与Makefile文件,目录树如下

│   
├── mydriver
│   ├── helloworld.c
│   └── Makefile

在helloworld.c中添加如下内容

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

static int __init hello_init(void)
 {
    printk(KERN_EMERG "[ KERN_EMERG ]  Hello  world Init\n");
    printk( "[ default ]  Hello  world Init\n");
 return 0;
}

static void __exit hello_exit(void)
{
    printk("[ default ]   Hello  world Exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL2");
MODULE_AUTHOR("embedfire ");
MODULE_DESCRIPTION("hello world module");

在Makefile中添加如下内容(注意Makefile的书写格式!),KERNEL_DIR、ARCH、CROSS_COMPILE需要替换为自己的路径与目标架构,KERNEL_DIR为官方SDK下的kernel层目录,CROSS_COMPILE为本文第1小节中提到的Toolchain

KERNEL_DIR=/home/username/ws/sdk/kernel/

ARCH=arm64

CROSS_COMPILE=/home/username/ws/sdk/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-

export ARCH CROSS_COMPILE

obj-m:=helloworld.o

all:
    $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules

.PHONE:clean

clean:
    $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
                                  

随后在/home/username/ws/mydriver/目录下执行make指令,当返回内容如下时代表成功编译驱动模块

make
# make -C /home/username/ws/sdk/kernel/ M=/home/username/ws/mydriver modules
# make[1]: Entering directory '/home/username/ws/sdk/kernel'
#   CC [M]  /home/username/ws/mydriver/helloworld.o
#   MODPOST /home/username/ws/mydriver/Module.symvers
#   CC [M]  /home/username/ws/mydriver/helloworld.mod.o
#   LD [M]  /home/username/ws/mydriver/helloworld.ko
# make[1]: Leaving directory '/home/username/ws/sdk/kernel'

可以看到此时在当前目录下生成很多文件,其中helloworld.ko为我们所需驱动文件,利用readelf -hl helloworld.ko可以查看该文件的简要信息(若没有readelf指令,可以使用sudo apt install binutils安装),其中Machine为AArch64,也即目标设备架构

3 运行驱动模块

运行驱动模块的步骤包括加载依赖与模块、查看模块、卸载模块,其中加载模块有两种方式:insmod与modprobe,区别可自行查找相关资料,这里会分别使用两种方式加载模块

3.1 insmod加载模块

使用insmod加载模块可在用户目录下的任意文件夹中实现,无需在/lib/modules/5.10.198中,使用scp将ubuntu主机上刚才编译出的.ko文件传到king3399从机中

scp helloworld.ko username_king@aaa.bbb.ccc.ddd:/home/username_king/ws/

加载该驱动模块

sudo /sbin/insmod helloworld.ko # 这里有.ko后缀

运行成功会看到相关日志以及在.c文件中需要打印的字串

查看模块列表

lsmod

卸载模块

sudo /sbin/rmmod helloworld # 这里没有.ko后缀

3.2 modprobe加载模块

使用modprobe加载模块必须进入/lib/modules/5.10.198目录,该目录出处可参考本文第1小节,使用scp将ubuntu主机上刚才编译出的.ko文件传到king3399从机中

scp helloworld.ko username_king@aaa.bbb.ccc.ddd:/lib/modules/5.10.198/

加载相关依赖

sudo /sbin/depmod

此处可能返回“WARING:could not open modules.order at…”和“WARING:could not open modules.builtin at…”,这两条警告可不用管

加载模块

sudo /sbin/modprobe helloworld # 这里没有.ko后缀!!!

运行成功会看到相关日志以及在.c文件中需要打印的字串

查看模块列表

lsmod

卸载模块

sudo /sbin/rmmod helloworld # 这里没有.ko后缀

[1] 野火-驱动章节实验环境搭建

[2] 《【野火】嵌入式Linux驱动开发实战指南—基于LubanCat RK系列板卡》

[3] 《【正点原子】ATK-DLRV1126嵌入式Linux驱动开发指南V1.2》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值