4.27.2009

實作一個假的 character driver 在emulator 上跑

大致上的做法就是將自己 build 的 kernel 放到 emulator, 然後再將自製假的 driver 放進 emulator 裡跑

1. 將 .config 從模擬器裡抓出來
因為模擬器裡的 kernel 的 CONFIG_MODULE 是關掉的。所以我們需要將它打開,否則不能 insmod 。
開了之後就要重 build 出 kernel image (zImage). 而要 build kernel 就需要模擬器裡的 kernel 的 .config。

先下載 Android 的 sdk , 因為 emulator 就在 SDK 裡,可到下面網址 download(註:我是以SDK 1.1為例子,SDK 1.5 還沒試過)


http://developer.android.com/sdk/1.1_r1/index.html



a. 解壓之後,執行 emulator


D:\workplace\android-sdk-windows-1.1_r1\tools>emulator


b. 在 emulator 執行的狀況下抓/proc/config.gz ,放到 \pulldata下


D:\workplace\android-sdk-windows-1.1_r1\tools>adb pull /proc/config.gz



2. 改 CONFIG_MODULES
將 config.gz 解壓之後放到 /mydroid/kernel 下, 然後找 CONFIG_MODULES ,並改為


CONFIG_MODULES=y



3. 改 kernel 的 Makefile
因為我們是跑 arm archtecture ,所以要改 tool chain
在 /mydroid/kernel/Makefile 裡,將 ARCH 跟 CROSS_COMPILE 改為下面


ARCH ?=arm
CROSS_COMPILE ?=../prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-


然後將 LDFLAGS_BUILD_ID mark 掉,如下


# LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,$(call ld-option, -Wl$(comma)--build-id,))


4. build kernel
(1) 先清乾淨


$make mrproper


(2) 將第二步驟的 config 改名為 .config ,放到 /mydroid/kernel 下
(3) make


$make


一開始會問你一些問題,一律都答N
build 完之後,會在 /mydroid/kernel/arch/arm/boot 找到 image, 叫 zImage

5. build fake driver
(1) 從 Linux Device Driver Programming 一書裡,copy 個範例 driver, source C 如下


/*
* devone.c
*
*/
#include linux/init.h
#include linux/module.h
#include linux/types.h
#include linux/kernel.h
#include linux/fs.h
#include linux/cdev.h
#include asm/uaccess.h

MODULE_LICENSE("Dual BSD/GPL");

static int devone_devs = 1; /* device count */
static int devone_major = 0; /* dynamic allocation */
static int devone_minor = 0;
static struct cdev devone_cdev;

ssize_t devone_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int i;
unsigned char val = 0xff;
int retval;

for (i = 0 ; i < count ; i++) {
if (copy_to_user(&buf[i], &val, 1)) {
retval = -EFAULT;
goto out;
}
}

retval = count;
out:
return (retval);
}

struct file_operations devone_fops = {
.read = devone_read,
};

static int devone_init(void)
{
dev_t dev = MKDEV(devone_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;

alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, "devone");
if (alloc_ret)
goto error;
devone_major = major = MAJOR(dev);

cdev_init(&devone_cdev, &devone_fops);
devone_cdev.owner = THIS_MODULE;
devone_cdev.ops = &devone_fops;
cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, devone_minor), 1);
if (cdev_err)
goto error;

printk(KERN_ALERT "devone driver(major %d) installed.\n", major);

return 0;

error:
if (cdev_err == 0)
cdev_del(&devone_cdev);

if (alloc_ret == 0)
unregister_chrdev_region(dev, devone_devs);

return -1;
}

static void devone_exit(void)
{
dev_t dev = MKDEV(devone_major, 0);

cdev_del(&devone_cdev);
unregister_chrdev_region(dev, devone_devs);

printk(KERN_ALERT "devone driver removed.\n");

}

module_init(devone_init);
module_exit(devone_exit);





Makefile 如下,你需要改 KERNELDIR ,這需要指到已經好的kernel,還有命令之前一定要是"tab"


KERNELDIR=/home/arik/Workspace/aydroid/kernel/
PWD := $(shell pwd)

obj-m := devone.o

modules:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules


clean:
rm -rf *.o *~ core.depend .*.cmd *.ko *.mod.c .tmp_versions




6. 將我們 build 的 zImage 放進 emulator 上跑


D:\workplace\android-sdk-windows-1.1_r1\tools>emulator.exe -kernel D:\workplace\
android-sdk-windows-1.1_r1\tools\lib\images\zImage


-kernel 後面的參數就是指到之前 build 出來的 kernel image

7. 把 busybox 放進 emulator
因為待會要用 busybox 的 mknod 指令( emulator 好像沒有), 所以要將 busybox 放進 emulator
(1) 讓 emulator 的 /system 這個目錄變成可 read/write. 開另一個 cmd 下


D:\workplace\android-sdk-windows-1.1_r1\tools>adb remount
* daemon not running. starting it now *
* daemon started successfully *
remount succeeded


(2) 下載 busybox


http://benno.id.au/android/busybox


(3) 把 busybox 放進 emulator


D:\workplace\android-sdk-windows-1.1_r1\tools>adb push busybox /system/bin
1703 KB/s (0 bytes in 1745016.001s)


(4) 更改 busybox 權限,否則不能用


D:\workplace\android-sdk-windows-1.1_r1\tools>adb shell
# chmod 566 /system/bin/busybox
chmod 566 /system/bin/busybox
#_



8. 把 ko 檔放進 emulator
跟放 busybox 一樣, 把假 driver 放進, 注意 emulator 裡只有 /system 目錄才可對外讀寫, 這裡我是放在 /system/bin


D:\workplace\android-sdk-windows-1.1_r1\tools>adb push devone.ko /system/bin
117 KB/s (0 bytes in 3763.000s)



9. 載入 module
跟在 linux 下做的一樣


D:\workplace\android-sdk-windows-1.1_r1\tools>adb shell
# busybox insmod /system/bin/devone.ko
busybox insmod /system/bin/devone.ko
# busybox lsmod
busybox lsmod
Module Size Used by Not tainted
devone 2624 0
#


10. 將 driver 掛上
掛上之前,要先知道它的 major id


# busybox cat /proc/devices
busybox cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
90 mtd
128 ptm
136 pts
252 devone
253 ttyS
254 rtc

Block devices:
1 ramdisk
7 loop
31 mtdblock
43 nbd
179 mmc
#


知道是 252 之後,就 mknod 上去


# busybox mknod /dev/devone c 252 0
busybox mknod /dev/devone c 252 0
# busybox ls -l /dev/devone
busybox ls -l /dev/devone
crw-rw-rw- 1 0 0 252, 0 Apr 30 02:26 /dev/devone
#


3 comments:

星痕 said...

請問一下大大

我照著你的步驟下去測試,前面都沒有問題


可是到了要掛載模組時,出現了錯誤

# busybox insmod /system/bin/devone.ko

insmod: cannot insert '/system/bin/devone.ko': invalid module format (-1): Exec format error

一直找不到解決的方法 請問大大知不知道這大概是什麼原因造成的呢?


謝謝^^

Anonymous said...

應該是compiler 版本的問題,
我之前也有遇到一樣的問題 ~
改了 Makefile 的 gcc 就解決了.

Kimi' Blog said...

大大請問一下
我在/mydroid/kernel 這個路徑上迷惑了,請問這個路徑是哪裡的??是從Andriod官網上下載下來的source code嗎?我現在下載的2.1版,裡面沒有kernel這個目錄,還是是我弄錯了。

此外,有另一個問題想請教,我們目前把Andriod安裝在一個netbook上,我們想把之前的linux driver安裝在這上面,我們driver在build的時候, KERNELDIR這個路徑應該指到source code的哪裡呢?

謝謝~~