《LINUX设备驱动程序》第三章提供了源码scull,但是由于我用的是5.4.0内核,书中的是2.6.10内核,内核发生了很大的变化,因此编译scull源码花费了不少时间,下面是编译调试记录。(这个编译调试记录应该是目前网络上适应内核版本最高的,所以也希望给近期加入《LINUX设备驱动程序》学习的小白们一个参考)。
一、main.c
1、make出现以下两个错误:
/home/valian/scull/main.c:17:26: fatal error: linux/config.h: 没有那个文件或目录
/home/valian/scull/main.c:32:46: fatal error: asm/system.h: 没有那个文件或目录
直接在main.c中删除这两个头文件.在新的内核里弃用了这两个.
2、copy_to_user copy_from_user
/home/valian/scull/main.c:324:6: error: implicit declaration of function ‘copy_to_user’ [-Werror=implicit-function-declaration]if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {^
/home/valian/scull/main.c: In function ‘scull_write’:
/home/valian/scull/main.c:373:6: error: implicit declaration of function ‘copy_from_user’ [-Werror=implicit-function-declaration]if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
新内核修改了这两个函数名称,更改如下:
copy_to_user()改为raw_copy_to_user();
copy_from_user()改为raw_copy_from_user();
3、access_ok
/home/valian/scull/main.c:414:68: error: macro "access_ok" passed 3 arguments, but takes just 2err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));^
/home/valian/scull/main.c:414:10: error: ‘access_ok’ undeclared (first use in this function)err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));^
/home/valian/scull/main.c:414:10: note: each undeclared identifier is reported only once for each function it appears in
/home/valian/scull/main.c:416:68: error: macro "access_ok" passed 3 arguments, but takes just 2err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
从错误提示看,大概是新内核的access_ok的参数为2个,但是原来内核为3个。
通过以下指令在源码中查找access的出出处:
find /lib/modules/5.4.0/build/include/linux -type f -exec grep "access_ok" {} ; -print
得到以下提示:
从提示看到新的access_ok的参数为(ptr,len),于是修改代码如下:
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
改为err = !access_ok((void __user *)arg, _IOC_SIZE(cmd));
4 、.ioctl (可参考CSDN-专业IT技术社区-登录)
make -C /lib/modules/5.4.0/build M=/home/valian/scull LDDINC=/home/valian/scull/../include modules
make[1]: Entering directory '/usr/src/linux-5.4'CC [M] /home/valian/scull/main.o
/home/valian/scull/main.c:558:2: error: unknown field ‘ioctl’ specified in initializer.ioctl = scull_ioctl,^
/home/valian/scull/main.c:558:14: error: positional initialization of field in ‘struct’ declared with ‘designated_init’ attribute [-Werror=designated-init].ioctl = scull_ioctl,
ioctl是未知域,同样检索ioctl
find /lib/modules/5.4.0/build/include/linux -type f -exec grep "ioctl" {} ; -print
得到(在/lib/modules/5.4.0/build/include/linux/fs.h)
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); // 5.4.0int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); // 2.6.10 网络上查找
对比发现.ioctl变为.unlocked_ioctl,函数指针的原型也变了,少了struct inode * 这个指针参数,而且函数类型也由int变为long。修改如下;
.ioctl = scull_ioctl改为 .unlocked_ioctl = scull_ioctl;
函数scull_ioctl改为(main.c 和scull.h)
long scull_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); // int 改为long,struct inode* 删除
5、init_MUTEX
/home/valian/scull/main.c: In function ‘scull_init_module’:
/home/valian/scull/main.c:653:3: error: implicit declaration of function ‘init_MUTEX’ [-Werror=implicit-function-declaration]init_MUTEX(&scull_devices[i].sem);
通过以下命令
find /lib/modules/5.4.0/build/include/linux -type f -exec grep "init_MUTEX" {} ; -print
查找,结果没有找到,应该是这个函数名称被弃用。在网络中找到解决方法init_MUTEX(&sem)被sema_init(&sem,1)替换了。
init_MUTEX(&scull_devices[i].sem); 改为sema_init((&scull_devices[i].sem),1);
sema_init的定义可参考/lib/modules/5.4.0/build/include/linux/semaphore.h
static inline void sema_init(struct semaphore *sem, int val)
pipe.c
1:init_MUTEX
同main.c,init_MUTEX改为sema_init;
//init_MUTEX(&scull_p_devices[i].sem);
sema_init((&scull_p_devices[i].sem),1);
2、signal_pending
/home/valian/scull/pipe.c: In function ‘scull_getwritespace’:
/home/valian/scull/pipe.c:172:7: error: implicit declaration of function ‘signal_pending’ [-Werror=implicit-function-declaration]if (signal_pending(current))
从错误代码查找关键词signal_pending的定义:
查找命令
find /lib/modules/5.4.0/build/include/linux -name '*.h' | xargs grep -w "signal_pending"
得到如下信息:
valian@valian-TM1703:~/scull$ find /lib/modules/5.4.0/build/include/linux -name '*.h' | xargs grep -w "signal_pending"
/lib/modules/5.4.0/build/include/linux/sched/signal.h:static inline int signal_pending(struct task_struct *p)
从signal_pending定义看函数参数没有改变,但是没有包含/linux/sched/signal.h头文件。
加上头文件:
#include <linux/sched/signal.h>
access.c
1、.ioctl 错误,参考上面的改正方法。
2、init_MUTEX
init_MUTEX(&(lptr->device.sem));改为sema_init(&(lptr->device.sem),1);
3、SPIN_LOCK_UNLOCKED
/home/valian/scull/access.c:98:34: error: ‘SPIN_LOCK_UNLOCKED’ undeclared here (not in a function)static spinlock_t scull_u_lock = SPIN_LOCK_UNLOCKED;
从提示看没有定义。查找关键词
find /lib/modules/5.4.0/build/include/linux -type f -exec grep "SPIN_LOCK_UNLOCKED" {} ; -print
得到以下信息
#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
/lib/modules/5.4.0/build/include/linux/spinlock_types.h
根据以上信息与源码中“static spinlock_t scull_u_lock = SPIN_LOCK_UNLOCKED;”对比发现,宏定义 DEFINESPINLOCK(x) 代替了源码中spinlock_t scull_u_lock = SPIN_LOCK_UNLOCKED。因此按以下修改即可。
//static spinlock_t scull_u_lock = SPIN_LOCK_UNLOCKED;
//static spinlock_t scull_c_lock = SPIN_LOCK_UNLOCKED;
//static spinlock_t scull_w_lock = SPIN_LOCK_UNLOCKED;static DEFINE_SPINLOCK(scull_u_lock) ;static DEFINE_SPINLOCK(scull_c_lock) ;static DEFINE_SPINLOCK(scull_w_lock) ;
4、uid euid
/home/valian/scull/access.c:108:29: error: ‘struct task_struct’ has no member named ‘uid’(scull_u_owner != current->uid) && /* allow user */^
/home/valian/scull/access.c:109:29: error: ‘struct task_struct’ has no member named ‘euid’(scull_u_owner != current->euid) && /* allow whoever did su */
查找关键词struct task_struct
find /lib/modules/5.4.0/build/include/linux -type f -exec grep "struct task_struct" {} ; -print
众多信息中找到定义在/lib/modules/5.4.0/build/include/linux/sched.h
struct task_struct {
...........
}
/lib/modules/5.4.0/build/include/linux/sched.h
但是查找sched.h中struct task_struct的定义,没有找到“uid,euid”。网络搜寻得知新的struct taskstruct 定义有变化,uid和euid在cred结构体中(在头文件/lib/modules/5.4.0/build/include/linux/cred.h中)。如下图找到uid,euid,其类型为kuid_t。
在</lib/modules/5.4.0/build/include/linux/uidgid.h>中查到kuid_t为结构体类型,定义如下:
typedef struct {uid_t val;
} kuid_t;
access.c中scull_u_owner的类型为static uid_t scull_u_owner。因此需要修改代码如下:
(current->uid改为current->cred->uid,current->euid改为current->cred->euid)
//scull_w_owner == current->uid ||
//scull_w_owner == current->euid ||
改为
scull_w_owner == current->cred->uid.val ||
scull_w_owner == current->cred->euid.val ||// (scull_u_owner != current->uid) && /* allow user */
// (scull_u_owner != current->euid) && /* allow whoever did su */
改为(scull_u_owner != current->cred->uid.val) && /* allow user */(scull_u_owner != current->cred->euid.val) && /* allow whoever did su */
过程中出现以下错误可参考[PATCH 0/5] PMFS: Rebase to Linux 3.9
/home/valian/SLAM/linux/scull/access.c:115:19: error: invalid operands to binary != (have ‘uid_t {aka unsigned int}’ and ‘kuid_t {aka const struct <anonymous>}’)(scull_u_owner != current->cred->uid) && /* allow user */^
/home/valian/SLAM/linux/scull/access.c:116:19: error: invalid operands to binary != (have ‘uid_t {aka unsigned int}’ and ‘kuid_t {aka const struct <anonymous>}’)(scull_u_owner != current->cred->euid) && /* allow whoever did su */
5、struct signal_struct
/home/valian/SLAM/linux/scull/access.c:283:22: error: dereferencing pointer to incomplete type ‘struct signal_struct’if (!current->signal->tty) {
错误提示可能是没有声明对应结构体定义的头文件。查找struct signal_struct的定义:
find /lib/modules/5.4.0/build/include/linux -type f -exec grep "struct signal_struct" {} ; -print
得到以下结果,在/lib/modules/5.4.0/build/include/linux/sched/signal.h。
struct signal_struct {
static inline void signal_set_stop_flags(struct signal_struct *sig,
static inline int signal_group_exit(const struct signal_struct *sig)
/lib/modules/5.4.0/build/include/linux/sched/signal.h
在assess.c中加上头文件;
#include <linux/sched/signal.h>
至此scull源码在内核linux5.4.0上编译通过。