本博客倡导开放源代码,在此公布之程序源代码如无特别声明均采用GNU通用公共 许可证(GPL)

乐在其中

分享学习Linux的乐趣

  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  23 随笔 :: 0 文章 :: 401 评论 :: 0 Trackbacks

#

在固件开发过程中常常遇到这样的情况:为测试某个新功能,必需修改某个系统文件。而这个文件在只读文件系统上(总不能为一个小小的测试就重刷固件吧),或者是虽然文件可写,但是自己对这个改动没有把握,不愿意直接修改。这时候mount --bind就是你的好帮手。

假设我们要改的文件是/etc/hosts,可按下面的步骤操作:

1. 把新的hosts文件放在/tmp下。当然也可放在硬盘或U盘上。
2. mount --bind /tmp/hosts /etc/hosts

测试完成了执行 umount /etc/hosts 断开绑定。

如果我需要在/etc下面增加一个exports文件怎么办?原来没有这个文件,不能直接bind。我们有两个方法:

方法1:绑定整个/etc目录,绑定前先复制/etc
# cp -/etc /tmp
# mount 
--bind /tmp/etc /etc
此时的/etc目录是可写的,所做修改不会应用到原来的/etc目录,可以放心测试。

方法2:挂载ramfs到/etc,同样要先复制/etc
挂载ramfs
# mkdir 
/tmp/etc
# mount 
-t ramfs none /tmp/etc

复制
/etc,这里我们不能用cp -a,改用tar
# cd 
/etc
# tar cf 
- . |(cd /tmp/etc; tar xf -)
# cd 
/

覆盖
/etc
# mount 
--move /tmp/etc /etc
测试完了记着 umount /etc

posted @ 2010-04-21 13:42 gouzhuang 阅读(40971) | 评论 (6)编辑 收藏

这段时间忙于研究工具链的升级、搭建QEMU编译和测试环境以及给Samba瘦身等等,没有及时更新博客,会在后续博文中给大家一一分享。

有朋友可能会问:为什么要自己费劲编译各种软件包,Optware不是提供大量交叉编译好的软件包吗?这得从海信MP800H播放机的局限性说起。

这款播放机是较早的产品,采用的是NOR闪存来存储固件,成本高因此配备的容量较低,只有16M。而较新的播放机多采用NAND闪存,比NOR成本低,容量可以做得更大(比如MP801H配备了256M的NAND闪存)。16M的空间里系统引导程序(Bootloader)和急救程序占了1280K,/usr/local/etc文件系统占了384K,在剩下的14.4M空间里要挤进Linux内核(约4M)、音频驱动(约1.8M)、视频驱动(约2.1M)以及根文件系统(约44M),看起来似乎是不可完成的任务。其实上面四大件经过压缩以后总共只有12M,所以我们还有2.4M的闪存空间可用,按照4:1的压缩比估算还可以挤进9.6M的内容。

因此在对MP800H进行扩展时,软件包的大小成为一个极其重要的考虑因素。Optware的软件包都是连接的/opt/lib下的动态库,其中包括uclibc。如果在固件中使用optware,则需要安装两套uclibc,这不仅浪费了宝贵的flash存储,也浪费了内存,因为内存中要加载两套uclibc。自己编译软件包可以确保只使用一套动态连接库,并且可以对软件包的大小进行优化。

前面在《固件解析》中已经提到,我们可以通过修改固件安装包里package1目录下有三个文件来制作自己的固件。这三个文件就是
  1. Linux内核:vmlinux.develop.avhdd.mars.bin.lzma
  2. 根文件系统:squashfs1.img
  3. /usr/local/etc文件系统:usr.local.etc.tar.bz2
关于内核的定制请参考《编译内核》。根文件系统的制作要用到squashfs工具中的mksquashfs命令。需要注意的是播放机内核中的squashfs的版本是3.1,因此一定要使用3.x版的工具(3.0和3.4都可以)来制作squashfs1.img,如果用4.0版的mksquashfs,内核将无法挂载根文件系统。至于/usr/local/etc文件系统,它是播放机上唯一可写的闪存分区,用于存放一些允许修改的配置文件。我们可以根据需要对/usr/local/etc进行定制,不过它的容量只有384K。

自己刷固件极有可能把播放机变砖,刷机前请一定准备好串口线。关于如何通过串口线救活砖机,请看蓝媒论坛dragon版主的大作《MP800H串口刷机指南》
posted @ 2010-04-10 22:24 gouzhuang 阅读(1815) | 评论 (5)编辑 收藏

     摘要: 通过hotplug程序实现USB无线网卡自动配置  阅读全文
posted @ 2010-03-26 18:04 gouzhuang 阅读(7521) | 评论 (50)编辑 收藏

为了在播放机上实现NFS服务器的功能,我们已经在uClibc中打开了完整RPC支持,并且在新编译的内核中打开了NFS服务器支持。此外还有两个软件包也是提供NFS服务所必需的:portmapnfs-utils。portmap为RPC程序提供端口映射服务,nfs-utils则是使用内核NFS服务器的支持程序。

编译portmap
1. 下载portmap_5beta: ftp://ftp.porcupine.org/pub/security/portmap_5beta.tar.gz
2. 打这个补丁: portmap_5beta.patch.zip (补丁来自buildroot-2009.11,我只是把多个补丁合并成一个)
3. $ make CC=mipsel-linux-gcc
4. $ mipsel-linux-strip portmap

编译nfs-utils
1. 下载nfs-utils-1.1.1: http://nchc.dl.sourceforge.net/project/nfs/nfs-utils/1.1.1/nfs-utils-1.1.1.tar.gz
2. 打这个补丁: nfs-utils-1.1.1-uclibc.patch.zip (在网上找到的,来源记不清了,我稍加了修改)
3. 运行配置脚本:
1 ./configure --build=i686-linux --host=mipsel-linux --disable-nfsv4 --disable-gss --disable-uuid --disable-mount --without-tcp-wrappers --with-gnu-ld CC=mipsel-linux-gcc CPP=mipsel-linux-cpp AR=mipsel-linux-ar STRIP=mipsel-linux-strip RANLIB=mipsel-linux-ranlib LD=mipsel-linux-ld
4. $ make
5. 安装到/home/user/dist/nfs-utils目录
1 $ make DESTDIR=/home/user/dist/nfs-utils install-strip

在制作固件时,我们只需要几个编译好的程序:portmap, rpc.statd, rpc.nfsd, rpc.mountd, exportfs。其中portmap 放到/sbin下,其余的放到/usr/sbin下。
此外还需要一个NFS服务启动脚本S60nfs,放在/etc/init.d目录下。下载脚本S60nfs.zip (来自buildroot,我把portmap的启动加进去了)
 1 #!/bin/sh                                
 2 #                                        
 3 # nfs           This shell script takes care of starting and stopping
 4 #               the NFS services. Stolen from RedHat FC5.            
 5 
 6 -/sbin/portmap ] || exit 0
 7 -/usr/sbin/rpc.statd ] || exit 0
 8 -/usr/sbin/rpc.nfsd ] || exit 0 
 9 -/usr/sbin/rpc.mountd ] || exit 0
10 -/usr/sbin/exportfs ] || exit 0  
11 
12 # Don't fail if /etc/exports doesn't exist; create a bare-bones version and continue.
13 -/etc/exports ] || \                                                             
14     { touch /etc/exports && chmod u+rw,g+r,o+/etc/exports ; } || \                 
15     { echo "/etc/exports does not exist" ; exit 0 ; }                                
16                                                                                      
17 # The /var/lib/nfs directory is actually on a tmpfs filesystem.                      
18 mkdir -/var/lib/nfs/sm                                                             
19 mkdir -/var/lib/nfs/sm.bak                                                         
20 touch /var/lib/nfs/etab                                                              
21 touch /var/lib/nfs/rmtab                                                             
22 touch /var/lib/nfs/state                                                             
23 touch /var/lib/nfs/xtab                                                              
24 
25 start() {
26         # Start daemons.
27         echo -"Starting port mapper: "
28         portmap                         
29         echo "done"                     
30 
31         echo -"Starting NFS statd: "
32         rpc.statd                     
33         touch /var/lock/subsys/nfslock
34         echo "done"                   
35 
36         echo -"Starting NFS services: "
37         /usr/sbin/exportfs -r            
38         rpc.statd                        
39         echo "done"                      
40 
41         echo -"Starting NFS daemon: "
42         rpc.nfsd 2                     
43         echo "done"                    
44 
45         echo -"Starting NFS mountd: "
46         rpc.mountd                     
47         echo "done"                    
48         touch /var/lock/subsys/nfs     
49 }                                      
50 
51 stop() {
52         # Stop daemons.
53         echo -"Shutting down NFS mountd: "
54         killall -q rpc.mountd               
55         echo "done"                         
56 
57         echo "Shutting down NFS daemon: "
58         kill -9 `pidof nfsd` 2>/dev/null 
59         echo "done"                      
60 
61         echo -"Shutting down NFS services: "
62         /usr/sbin/exportfs -au                
63         rm -/var/lock/subsys/nfs            
64         killall -q rpc.statd                  
65         echo "done"
66 
67         echo -"Stopping NFS statd: "
68         killall -q rpc.statd
69         echo "done"
70         rm -/var/lock/subsys/nfslock
71 
72         echo -"Stopping port mapper: "
73         killall -q portmap
74         echo "done"
75 }
76 
77 # See how we were called.
78 case "$1" in
79   start)
80         start
81         ;;
82   stop)
83         stop
84         ;;
85   restart)
86         stop
87         start
88         ;;
89   reload)
90         /usr/sbin/exportfs -r
91         touch /var/lock/subsys/nfs
92         ;;
93   *)
94         echo "Usage: nfs {start|stop|reload}"
95         exit 1
96 esac
97 
98 exit 0

posted @ 2010-03-23 16:24 gouzhuang 阅读(8089) | 评论 (4)编辑 收藏

Linux内核负责管理/调度所有的系统资源和设备,并为应用程序提供服务。要想让播放机支持更多的设备,比如USB无线网卡,必需从内核入手。Linux支持动态加载模块,这些模块其实也是内核的一部分,只不过是被模块化罢了。模块化的好处之一是可以在需要时才加载模块,不需要时可以卸载,释放其占用的内存。这对内存紧张的嵌入式系统无疑是有帮助的。

我重新编译内核有以下几个目的:
1) 打开官方内核中某些没有打开的功能,如NFS服务器。
2) 尝试支持更多外部设备,如编译第三方驱动程序。
3) 内核瘦身,比如关闭某些不需要的功能,或者将其编译成模块。

内核源码仍使用华硕公布的源码,其中名为linux-2.6.12.274877.tgz的文件即是内核源码。用tar zxf linux-2.6.12.274877.tgz解开此文件,得到linux-2.6.12目录。看一下版本号
1 $ grep UTS_RELEASE linux-2.6.12/include/linux/version.h
2 #define UTS_RELEASE "2.6.12.6-VENUS"
与在播放机上用'uname -r'看到的一样,因此我们能确信这就是播放机所用内核的源码,虽然来源不是海信,但是我认为海信不会在内核上做什么改动,最多不过调整一些配置参数。

粗略研究了一下内核源码,发现Realtek在原始的2.6.12.6内核基础上做了不少修改,下面列出其中一部分:
  1. 文件系统方面增加了
    • fuse - Filesystem in Userspace
    • ptp - Picture Transfer Protocol,用于数码相机
    • vcd - CDROM文件系统
    • squashfs - 压缩的只读文件系统
    • yaffs - 针对NAND闪存优化的文件系统
  2. 大量的MIPS平台更新,其中包括对Realtek Venus系统(就是播放机所用系统)的支持
  3. 增加了Realtek无线网卡支持,包括RTL8185,RTL8187,RTL8190,RTL8192,RTL8191SU等芯片组的支持。
  4. 增加了一些专门针对Realtek Venus的优化
linux-2.6.12目录下有两个配置文件样本:config.develop.avhdd.mars.old 和 config.rescue.usb.flash.mars.old。根据字面意思推测第一个文件是常规模式的内核配置,第二个是急救模式的内核配置。急救模式只保留了急救固件升级所需功能,因此编译出的内核比常规模式的小很多。在MP800H上,急救内核与Bootloader放在同一个flash分区内,正常的固件升级不会更新这一部分。关于通过串口激活急救模式进行固件升级的方法,请看蓝媒论坛dragon版主的大作《MP800H串口刷机指南》
我以config.develop.avhdd.mars.old为基准对内核进行配置(执行make menuconfig),打开了NFS Server Support(编译成模块,并且只打开NFSv3支持),其余部分保持不变,最后得到的.config文件增加了如下几项:
1 CONFIG_NFSD=m
2 CONFIG_NFSD_V3=y
3 CONFIG_NFSD_TCP=y
4 CONFIG_EXPORTFS=m
然后执行make进行编译(注意:编译内核要用/usr/bin下的工具链,即mipsel-sdelinux-v6.03.01-1,在PATH中/usr/bin应该在/usr/local/bin的前面)。编译完成后会生成名为vmlinux.bin的文件,用lzma把它压缩后改名为vmlinux.develop.avhdd.mars.bin.lzma,这个文件即可用于制作固件。另外还需要把编译好的模块安装到某个目录以便于打包,比如要安装到/home/user/dist/modules则执行如下命令:
1 make INSTALL_MOD_PATH=/home/user/dist/modules modules_install
至此,我们已经准备好了新的内核和模块。在用自己编译的模块替换官方固件模块时要注意两点:
1. 如果配置内核是打开了DEBUG,编译出的模块会很大,在制作固件前最好把调试信息去掉。下面的命令可以很容易的完成这个任务:
1 $ cd /home/user/dist/modules
2 $ find . -name '*.ko' -exec mipsel-linux-strip --strip-unneeded '{}' \;
2. 有一个模块ufsd.ko是没有源码的,这个模块提供NTFS读写的支持。如果你想使用NTFS,则要从官方固件中拷贝这个文件。

posted @ 2010-03-21 21:49 gouzhuang 阅读(9284) | 评论 (132)编辑 收藏

     摘要: uClibc和BusyBox已经编译好了 ,在把它们加入固件之前最好先测试一下。测试方法是建立一个模拟的根文件系统,通过chroot命令来建立一个新的执行环境,在这个环境下所执行的命令以及动态连接库都来自于这个模拟的根文件系统。模拟根文件系统的制作方法(在PC上执行):准备一个U盘或移动硬盘,格式化成ext3文件系统。假设编译好的uClibc和BusyBox分别放在/home/user/dist...  阅读全文
posted @ 2010-03-18 23:37 gouzhuang 阅读(2012) | 评论 (1)编辑 收藏

MP800H官方固件中使用的uClibc版本为0.9.28,也是相当老的版本(2005年发布的)。但是由于现有的工具链都是基于这个版本的,到目前为止,升级到新版本的尝试还不成功的。(这不是目前最紧迫的任务,我会晚点再研究)

既然不升级,为什么还要重新编译呢?因为官方编译的版本没有打开完整RPC支持(配置文件中:UCLIBC_HAS_FULL_RPC=y),没有它NFS服务器不能工作。

还是用华硕公布的源码。华硕在uClibc-0.9.28官方源码基础上做了一些修改(我把它整理成针对官方版的补丁:uClibc-0.9.28-asus.patch.zip
工具链就用华硕源码包里提供的sdelinux-5.03.06-1

配置uClibc:进入uClibc-0.9.28源码目录,执行make menuconfig进行交互是配置。(我用的配置:config-uclibc-0.9.28.zip,可直接将此配置文件解压后改名为.config放入uClibc源码目录,然后再执行make menuconfig在此基础上进行修改)。

配置时有一点需要注意:有一项配置叫做"Linux kernel header location",需要填入Linux内核头文件的路径,这个必需与播放机上运行的内核版本一致。这里我还是用华硕的Linux内核源码。源码包里有个文件叫linux-2.6.12.274877.tgz,将它解开 tar zxf linux-2.6.12.274877.tgz,得到linux-2.6.12目录,将"Linux kernel header location"指向这个目录。


配置完成后执行make进行编译,然后安装到指定目录以便于打包,这里以/home/user/dist/uclibc为例
1 make PREFIX=/home/user/dist/uclibc install

到这里,我们已经有了自己编译的uClibc和BusyBox,下一步就是要测试一下它们是否能正常工作。我将在下一篇博文中介绍。
posted @ 2010-03-18 15:16 gouzhuang 阅读(5867) | 评论 (4)编辑 收藏

海信MP800H官方固件里的busybox版本是1.1.3,是2006年发布的,确实有点老旧。最新的稳定版是2009年12月发布的1.15.3,与1.1.3版相比修正了很多bug并增加了一些新的应用程序(applet),特别是增加了ftpd。当然也有一些应用被删除了:e2fsprogs(ext2/ext3文件系统工具: mke2fs, e2fsck, tune2fs等),原因是它相对于busybox来说太大了。其实e2fsprogs并非播放机必需的,而且这些工具可以在台式机上获得。因此我决定要把busybox升级到1.15.3。

华硕公布的源码中busybox-1.1.3有一部分被修改过,其中init增加了对SIGABRT(6)信号的处理,当init进程收到此信号时(kill -6 1),将触发固件升级程序。详细过程请看/etc/reexec_init下的脚本。我希望能保留该功能,将它移植到1.15.3(见补丁:busybox-1.15.3-reexec_init.patch.zip

另外,目前busybox测试版1.16.0中新增了ntpd,我把它给backport到1.15.3(见补丁:busybox-1.15.3-ntpd.patch.zip)。ntpd 对MP800H来说相当重要,因为播放机没有电池为时钟供电,只要重新加电系统时间就会重置,有了ntpd就可实现与ntp服务器自动时间同步。

编译busybox-1.15.3
1) 下载源码 http://www.busybox.net/downloads/busybox-1.15.3.tar.bz2
2) 解压
1 $ tar jxf busybox-1.15.3.tar.bz2
3) 打补丁
 1 $ ls -l
 2 总用量 113
 3 drwxr-xr-31 user users   1224 2009-12-13 05:18 busybox-1.15.3
 4 -rw-r--r--  1 user users 108352 2010-03-16 14:51 busybox-1.15.3-ntpd.patch
 5 -rw-r--r--  1 user users   3216 2010-03-16 14:51 busybox-1.15.3-reexec_init.patch
 6 $ cd busybox-1.15.3/
 7 $ patch -p1 < ../BusyBox-1.15.3-ntpd.patch
 8 patching file include/applets.h
 9 patching file include/libbb.h
10 patching file include/usage.h
11 patching file libbb/messages.c
12 patching file networking/Config.in
13 patching file networking/Kbuild
14 patching file networking/ntpd.c
15 patching file networking/ntpd_simple.c
16 $ patch -p1 < ../BusyBox-1.15.3-reexec_init.patch
17 patching file init/Config.in
18 patching file init/init.c
4) 配置busybox
1 $ make menuconfig
配置完成后会生成一个.config文件,注意前面有个点。这是我的配置文件:config-busybox-1.15.3.zip
5) 编译
1 $ make
6) 安装到指定的目录,比如/home/user/dist/busybox
1 $ make CONFIG_PREFIX=/home/usr/dist/BusyBox install

补充
用华硕提供的工具链sdelinux-5.03.06-1进行编译时会报ULLONG_MAX undeclared的错误。解决办法是对其中一个头文件打下面的补丁:
头文件:/usr/local/lib/gcc-lib/mipsel-linux/2.96-sdelinuxmips-040127/include/limits.h
补丁如下:
--- limits.h.orig       2004-02-12 20:38:47.000000000 +0800
+++ limits.h    2010-03-02 08:53:11.984943511 +0800
@@ 
-94,5 +94,12 @@
 #define ULONG_LONG_MAX (LONG_LONG_MAX 
* 2ULL + 1)
 #endif

+/* Minimum and maximum values a `signed long long int' can hold.  */
+#define LLONG_MAX    9223372036854775807LL
+#define LLONG_MIN    (-LLONG_MAX - 1LL)
+
+/* Maximum value an `unsigned long long int' can hold.  (Minimum is 0.)  */
+#define ULLONG_MAX   18446744073709551615ULL
+
 #endif 
/* _MACH_MACHLIMITS_H_ */
 #endif 
/* _LIMITS_H___ */

posted @ 2010-03-16 15:58 gouzhuang 阅读(6598) | 评论 (45)编辑 收藏

RTD1073是基于32位MIPS指令集的,与我们常用的x86平台是不兼容的。为了能够生成在RTD1073上运行的程序,必然要用到交叉编译工具。
简单说,交叉编译就是在一个平台(编译平台/build platform)上生成另一个平台(目标平台/target platform)的执行代码。通常目标平台是一些运算能力较弱的嵌入式系统。交叉编译工具链(cross compile tool chain)是指用于交叉编译的一系列工具,主要包括C/C++编译器、函数库(libc, libstdc++等)、binutils等。C函数库libc常用的有两种:大而全的glibc(GNU C Library) 和小巧的uClibc。嵌入是系统由于受内存和flash存储空间的限制,通常都使用uClibc。
早前提到的华硕的公开源码包中提供了有两套工具链:一套用于应用程序编译,一套用于Linux内核编译,并附有安装说明。在网上搜搜还能找到其它厂商公布的源码和工具链,只要是基于RTD1073或其姊妹产品的,内核源码和工具链都是一样的,相信它们都源自Realtek。
交叉编译工具常常在命令前加一个前缀,比如上述两套工具链都使用'mipsel-linux-'的前缀。如果将两套工具链安装在一个系统里,可以通过PATH环境变量来选择所用的工具链。具体地说,用于AP(应用程序)的工具链安装在/usr/local/bin;用于内核的工具链安装在/usr/bin。要选择AP工具链就在PATH中将/usr/local/bin放在/usr/bin前面,反之亦然。
写一个hello.c程序试试看
1 #include <stdio.h>
2 int main(int argc, char* argv[]) {
3    printf("Hello, world!\n");
4 }
编译
 1 $ which mipsel-linux-gcc
 2 /usr/local/bin/mipsel-linux-gcc
 3 $ mipsel-linux-gcc -o hello hello.c
 4 $ ls -l hello
 5 -rwxr-xr-1 user users 7749 2010-03-16 12:00 hello
 6 $ file hello
 7 hello: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
 8 $ mipsel-linux-strip hello
 9 $ file hello
10 hello: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), stripped
11 $ ls -l hello
12 -rwxr-xr-1 user users 5536 2010-03-16 12:01 hello
把编译生成的hello文件拷贝的U盘上,然后插入到MP800H上,telnet上去运行一下,Bingo! 打印出Hello, world!
posted @ 2010-03-16 12:55 gouzhuang 阅读(3326) | 评论 (3)编辑 收藏

     摘要: 分析了海信官方发布的MP800H高清播放机固件的结构,为自制固件奠定了基础。  阅读全文
posted @ 2010-03-16 09:29 gouzhuang 阅读(3806) | 评论 (1)编辑 收藏

仅列出标题
共3页: 1 2 3