前言
最近在学习老罗博客,看到他的《在Ubuntu上为Android系统编写Linux内核驱动程序》一文(文章链接),自己也跃跃欲试,不过教程是基于goldfish-2.6.29内核的,而我的环境是android 6.0,goldfish-3.10内核的,在编译过程中遇到的问题我都会在本文记录下来。
问题汇总
(1) expected ‘kgid_t’ but argument is of type ‘int’
这个问题的缘由是因为 kgid_t 在新内核被重新定义了:
//include/linux/uidgid.h
typedef struct {
uid_t val;
} kuid_t;
typedef struct {
gid_t val;
} kgid_t;
#define KUIDT_INIT(value) (kuid_t){ value }
#define KGIDT_INIT(value) (kgid_t){ value }
可以采用新添加的宏,于是作如下patch:
--- old_commoncap.c 2016-06-03 16:00:18.264161532 +0800
+++ commoncap.c 2016-06-03 15:58:11.512638732 +0800
@@ -83,9 +83,9 @@ int cap_capable(const struct cred *cred,
struct user_namespace *ns = targ_ns;
#ifdef CONFIG_ANDROID_PARANOID_NETWORK
- if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW))
+ if (cap == CAP_NET_RAW && in_egroup_p(KGIDT_INIT(AID_NET_RAW)))
return 0;
- if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN))
+ if (cap == CAP_NET_ADMIN && in_egroup_p(KGIDT_INIT(AID_NET_ADMIN)))
return 0;
#endif
编译通过。
编译过程中还有几处用到 in_egroup_p 的地方都会有相同错误,采取同样方式修改即可。
(2) implicit declaration of function ‘create_proc_entry’
在新版内核中用 proc_create 代替了 create_proc_entry:
//include/linux/proc_fs.h
static inline struct proc_dir_entry *proc_create(
const char *name, umode_t mode, struct proc_dir_entry *parent,
const struct file_operations *proc_fops)
{
return proc_create_data(name, mode, parent, proc_fops, NULL);
}
作如下patch:
--- old_hello.c 2016-06-03 14:44:03.787546702 +0800
+++ hello.c 2016-06-03 14:49:54.442698524 +0800
@@ -205,15 +205,7 @@ out:
static void hello_create_proc(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);
- if(entry)
- {
- entry->owner = THIS_MODULE;
- entry->read_proc = hello_proc_read;
- entry->write_proc = hello_proc_write;
- }
+ proc_create(HELLO_DEVICE_PROC_NAME, 0, NULL, &hello_proc_fops); //注意此处的"hello_proc_fops"
}
在老罗的文章评论中我看到有读者曾经试过将create_proc_entry换成proc_create后,编译成功,但在adb shell 执行 cat /proc/hello 会导致内核崩溃,原因是直接把之前定义的 hello_fops 结构体原封不动传入了proc_create函数。目前我也没找到以最小改动完成修正的方法,在网上搜了一下关于proc_create的用法(
例子),很多都是采用了 seq_file 的方法(
kernel源码中的seq_file文档说明)。所以我这里提供一种修改的方法,即重新定义一个file_operations 结构体“hello_proc_fops” 传入 proc_create,如有不妥希望大家见谅并指出:
static int hello_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", hello_dev->val);
return 0;
}
static int hello_proc_open(struct inode *inode, struct file *filp)
{
return single_open(filp, hello_proc_show, NULL);
}
static ssize_t hello_proc_write(struct file *filp, const char __user *buff, size_t count, loff_t *pos)
{
int err = 0;
char *page = NULL;
if(count > PAGE_SIZE)
{
printk(KERN_ALERT "The buff is too large: %lu.\n", count);
return -EFAULT;
}
page = (char *)__get_free_page(GFP_KERNEL);
if(!page)
{
printk(KERN_ALERT "Failed to alloc page.\n");
return -ENOMEM;
}
if(copy_from_user(page, buff, count))
{
printk(KERN_ALERT "Failed to copy buff from user.\n");
err = -EFAULT;
goto out;
}
err = __hello_set_val(hello_dev, page, count);
out:
free_page((unsigned long)page);
return err;
}
static struct file_operations hello_proc_fops = {
.owner = THIS_MODULE,
.open = hello_proc_open,
.write = hello_proc_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release
};
static void hello_create_proc(void)
{
proc_create(HELLO_DEVICE_PROC_NAME, 0, NULL, &hello_proc_fops);
}
注意需要添加头文件 <linux/seq_file.h>。
经测试,编译通过,cat /proc/hello 和 echo写操作均正常。
(3) error: implicit declaration of function ‘init_MUTEX’
static inline void init_MUTEX (struct semaphore *sem)
{
sema_init(sem, 1);
}
static inline void init_MUTEX_LOCKED (struct semaphore *sem)
{
sema_init(sem, 0);
}
因此直接使用sema_init,作如下patch:
--- old_hello.c 2016-06-03 14:44:03.787546702 +0800
+++ hello.c 2016-06-03 15:09:44.623456649 +0800
@@ -240,7 +232,7 @@ static int __hello_setup_dev(struct hell
return err;
}
- init_MUTEX(&(dev->sem));
+ sema_init(&(dev->sem), 1);
dev->val = 0;
return 0;
(4) error: implicit declaration of function ‘kmalloc’ and ‘kfree’
(5) error: type mismatch in conditional expression (sock_i_uid问题)
此error与(1)中error同理,也是由于 kuid_t 被重新定义了,故运用新定义的宏即可:
sk ? sock_i_uid(sk) : KUIDT_INIT(0)
总结
以上基本上就是本人编译过程中遇到的问题,解决了之后就可以编译通过了。值得注意的是,编译的内核是给emulator用的,所以用的config文件是:
运行:
欢迎交流交流~
./kernel/goldfish/arch/x86/configs/x86_64_emu_defconfig
之后再make menuconfig进行自定义模块的选定就ok了。
运行:
emulator -kernel kernel/goldfish/arch/x86/boot/bzImage
可从手机信息里看出内核版本: