原文出处:刘建文 | 学术半·IT歌·文(http://arttech.us)
我是一位理论帝,想问题做事情更多的会从形而上的角度入手。这个结论的证据之一,是从我研究学习嵌入式Linux近一年后才决定购一台掌上电脑做实验。年初的时候就有朋友建议我购一块开发板,通过做实验快速掌握开发技术。但我并不以为然,首先,我认为基本功更重要,开发技术可短期内习得;什么是基本功,对内核结构的深度把握,对硬件的透彻理解;其次,我想我花三五百购块开发板做完后还有什么用?前一个想法的结果是十月底我才购一台机器做实验,后一想法的结果是我购的是诺基亚的n800,而不一次性的祼机板。
到目前为止我在n800上做了两个简单的实验,本文记录实验全程,不求同和,但求录之以照后来人。
第一个实验交叉编译一个hello模块到n800上,验证开发环境和开发硬件等的可用性;第二个实验是定制一个新内核到n800上,新内核中触摸屏和小键盘以模块形式加载,而非默认的内置。
1. 下载maemo4.1源码和补丁 :http://repository.maemo.org/pool/maemo4.1.2/free/k/kernel-source-diablo/
2. 解包并进补:
$ patch -p2 < kernel-source-diablo_2.6.21-200842maemo1.diff
3. 安装pre-build交叉编译工具链 :http://www.codesourcery.com/sgpp/lite/arm/releases/2005q3-2
这是一个商业免费版预编译工具链,直接解压到~/n800/cross-toolchain/下即可
4. 添加shell搜索路径
$ export PATH=~/n800/cross-toolchain/bin:$PATH
5. 测试源码树与交叉编译工具链的可用性
$cd ~/n800/maemo/kernel-source-diablo/kernel-source
$cp arch/arm/configs/nokia_2420_defconfig .confg
$make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- bzImage
此官方源码竟然有一个符号声明丢失:scripts/mod/sumversion.c PATH_MAX undeclared
修复办法:modifying linux-2.6.x/scripts/mod/sumversion.c, and adding #include <limits.h> fixes this issue.
成功编译内核后证明交叉编译工具链和源码树可用。编译源码树一遍为编译外部模块作准备(也可以通过执行kbuild接口 make modules_prepare) ,因为编译外部模块会对内核的一些信息有依赖,像内核输出符号(Module.symvers)。详见内核文档Document/kbuild/modules.txt
--- 2.4 Preparing the kernel tree for module build
To make sure the kernel contains the information required to build external modules the target 'modules_prepare' must be used. 'modules_prepare' exists solely as a simple way to prepare a kernel source tree for building external modules. Note: modules_prepare will not build Module.symvers even if CONFIG_MODVERSIONS is set. Therefore a full kernel build needs to be executed to make module versioning work.
1.enable USB networking support in the kernel.
# # USB Network Adapters #
CONFIG_USB_USBNET=m
CONFIG_USB_NET_CDCETHER=m
2.安装usbnet模块
Linux-PC: $ modprobe usbnet
3.配置usb网络接口
通过ifup的配置文件(/etc/sysconfig/network-scripts/ifcfg-usb0)实现:
DEVICE=usb0
BOOTPROTO=static
IPADDR=192.168.2.14
# IPADDR=10.0.1.2/24 should imply this ...
# but its support code seems to be buggy.
BROADCAST=192.168.2.255
NETMASK=255.255.255.0
NETWORK=192.168.2.0
# this is likely to break sometime
GATEWAY=192.168.2.1
ONBOOT=yes
4.启用网络接口
Linux-PC: $ ifup usb0
1.取得root权限并安装ether_over_usb模块(g_ether.ko):
取得root权限的方法有两种,第一,开启机器的R&D模式,使用gainroot;第二种这是安装rootsh包,直接用root命令最得权限:
Nokia-N800: $ id uid=29999(user) gid=29999 (users)
#if use r&d mode
Nokia-N800: $ sudo /usr/sbin/gainroot
#or use rootsh
Nokia-N800: $ root
Nokia-N800: # insmod /mnt/initfs/lib/modules/2.6.18-omap1/g_ether.ko
2.启用网络接口
Nokia-N800: # ifup usb0
3.测试连通性
Nokia-N800: # ping 192.168.2.14
如果不通,再插拔一下USB线
Linux-PC $ssh -l root 192.168.2.15
pw:111111 (此密码在安装OpenSSH时设置)
传送文件 Linux-PC $ scp ~/n800/projects/modulize_kernel/tsc2301_kp.ko [email protected]:
1. 编写源文件hello_mod.c
01
/* hello_mod.c */
02
#include <linux/init.h>
03
#include <linux/module.h>
04
#include <linux/kernel.h>
05
06
static int
hello_init
(
void
)
07
{
08
printk
(
KERN_ALERT "Hello, world
/n
"
);
09
return
0
;
10
}
11
12
static void
hello_exit
(
void
)
13
{
14
printk
(
KERN_ALERT "Goodbye, cruel world
/n
"
);
15
}
16
17
module_init
(
hello_init);
18
module_exit
(
hello_exit);
19
MODULE_LICENSE
(
"GPL"
);
2. 编写kbuild Makefile
01
# Makefile for the hello module
02
obj-m :=
hello_mod.o
03
KDIR :=
~/
n800/
maemo/
kernel-source-diablo/
kernel-source
04
PWD := $(
shell
pwd)
05
default:
06
$(
MAKE) -
C $(
KDIR)
M=$(
PWD)
modules
3. 编译
$ cd ~/n800/projects/hello_module
$ export PATH=~/n800/cross-toolchain/bin:$PATH
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
4.测试把编译得到的hello_mod.ko 通过ssh下载到n800进行测试,过程略。
1. 配置内核
配置任务是把小键盘和触摸屏的驱动改为模块,官方内核是build-in 的。
$ cd ~/n800/maemo/kernel-source-diablo/kernel-source
$ cp arch/arm/configs/nokia_2420_defconfig .config
# 配置文件库(arch/arm/configs)还有一个n800_defconfig,此配置不适合OS2008
$ make menuconfig
2. 配置项如下,可以在配置程序内查找其所在位置,配置过程略
CONFIG_KEYBOARD_TSC2301=m
CONFIG_TOUCHSCREEN_TSC2301=m
3. 检查配置结果:
$ cat .config | grep TSC2301
CONFIG_KEYBOARD_TSC2301=m
CONFIG_TOUCHSCREEN_TSC2301=m
CONFIG_SPI_TSC2301=y
CONFIG_SPI_TSC2301_AUDIO=y
4. 编译内核
$ export PATH=~/n800/cross-toolchain/bin:$PATH
$ export ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
$ make zImage
$ cp arch/arm/boot/zImage ~/n800/projects/modulize_kernel
5. 编译模块
$ INSTALL_MOD_PATH=~/n800/projects/modulize_kernel
$ make modules
$ make modules_install
initramfs是kernel 的[前根文件系统]引导功能(他们用了一个新概念叫early-userspace)的2.6版新实现,前2.6版的是众所周知的initrd。 initramfs不再是核外的一个虚拟盘,而是核内的内存根文件系统一个镜像,filesystem是使用缓存机制实现的tempfs。简单的理解是,initramfs是正在内存中运行的内核的根文件系统被转存(object dump)到磁盘上的映像。为了实现更好灵活性,新版内核的[前根文件系统]还是提供了[核内核外]配置的方式。核外配置的表象与initrd很像,但是完全不同的概念,内核使用完全不同的代码解读前根文件系统,initramfs只是一个cpio档,被bootloader调入内存后,内核会自动识别,进行链接。
1. 下载固件( http://tablets-dev.nokia.com/nokia_N800.php )并解包至 ~/n800/firmware
2. 下载并安装官方的擦写程序flash3.5(这里也可以使用一个开源的擦写程序0xFFFF)直接解压到~/n800/build-tools/flasher/即可
3. 解包固件至./firmware/43-7-fiasco
$ cd ~/n800/firmware
$ mkdir 43-7-fiasco;cd 43-7-fiasco
$ ~n800/build-tools/flasher-3.5 -F ~/n800/firmware/RX-34_DIABLO_5.2008.43-7_PR_COMBINED_MR0_ARM.bin -u
4. initramfs.jffs2 是jffs2镜像,先作成虚拟盘
$ mknod /tmp/mtdblock0 b 31 0
$ mkdir /mnt/initfs
$ modprobe loop
$ losetup /dev/loop0 ~/n800/firmware/43-7-fiasco/initfs-0.95.22-200842maemo1w38b3
$ modprobe mtdblock
$ modprobe block2mtd
# Note the ,128KiB is needed (on 2.6.26 at least) to set the eraseblock size.
$ echo "/dev/loop0,128KiB" > /sys/module/block2mtd/parameters/block2mtd
$ modprobe jffs2
$ mount -t jffs2 /tmp/mtdblock0 /mnt/initfs/
5. 虚拟盘不能直接修改,必须拷出来,修改后再用MTD tool(mkfs.jffs2)重制作initramfs 镜像
$ mkdir /mnt/tmp/initramfs
$ cp -a /mnt/initfs/ /mnt/tmp/initramfs
6. 拷贝驱动模块并修改启动脚本linuxrc
$ cp ~/n800/projects/modulize_kernel/tsc2301_kp.ko /mnt/tmp/initramfs/lib/modules/omapXXX/
$ cp ~/n800/projects/modulize_kernel/tsc2301_ts.ko /mnt/tmp/initramfs/lib/modules/omapXXX/
$ echo "insmod $MODULE_PATH/tsc2301_kp.ko" >> /mnt/tmp/initramfs/linuxrc
$ echo "insmod $MODULE_PATH/tsc2301_kp.ko" >> /mnt/tmp/initramfs/linuxrc
7. 重制作initramfs 镜像(http://sources.redhat.com/jffs2/ )
$ mkfs.jffs2 -n -r /mnt/tmp/initramfs -e 20000 -o rootfs.jffs2
P.S. 事后发现原来可以直接在n800的maemo上修改,要修改,得行把initramfs闪存分区重挂接为可读写:
Nokia-N800: # mount -o remount,rw /dev/mtdblock3 /mnt/initramfs
$ cd ~/n800/build-tools/
$ flash3.5 -k ~/n800/projects/modulize_kernel/zImage -f
#提示接入n800,把n800接好USB线,按住HOME键再开机
$ flash3.5 -n ~/n800/projects/modulize_kernel/initramfs.jffs2 -f -R
重启后测试,测试过程略。