Android Linux内核驱动程序(基于goldfish-3.10内核)

前言


        最近在学习老罗博客,看到他的《在Ubuntu上为Android系统编写Linux内核驱动程序》一文(文章链接),自己也跃跃欲试,不过教程是基于goldfish-2.6.29内核的,而我的环境是android 6.0,goldfish-3.10内核的,在编译过程中遇到的问题我都会在本文记录下来。

问题汇总


(1) expected ‘kgid_t’ but argument is of type ‘int’


Android Linux内核驱动程序(基于goldfish-3.10内核)_第1张图片

        这个问题的缘由是因为 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);
}
        注意需要添加头文件
        经测试,编译通过,cat /proc/hello 和 echo写操作均正常。

(3) error: implicit declaration of function ‘init_MUTEX’ 



        在新版内核中已经去掉了 init_MUTEX 的定义,在2.6内核里的定义如下:
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’ 


        在hello.c包含头文件即可(#include )。

(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
可从手机信息里看出内核版本:

Android Linux内核驱动程序(基于goldfish-3.10内核)_第2张图片

        欢迎交流交流~


你可能感兴趣的:(Android,Linux)