Chinaunix首页 | 论坛 | 博客
  • 博客访问: 626108
  • 博文数量: 144
  • 博客积分: 5037
  • 博客等级: 大校
  • 技术积分: 1581
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-30 21:49
文章存档

2010年(16)

2009年(128)

分类: LINUX

2009-10-20 16:44:53

uClinux 在 S3C4510B 嵌入式开发板上的移植和开发详解(转载过来)
 
刘 朋 (liupcdl@cn.ibm.com), 软件工程师, IBM

2007 年 12 月 20 日

    本文对 uClinux 在 S3C4510B 嵌入式开发板上的移植、网络服务设置、驱动以及用户程序开发等问题进行了较为详细的介绍。本文中所总结的经验可供在上述嵌入式环境下工作的开发人员借鉴,也能为其他嵌入式平台的开发提供一定的启发。
嵌入式系统的特点在于:针对特定的应用,使用“量体裁衣”的方式将所需的功能嵌入到各种应用系统当中。其早期主要应用于军事及航空、航天领域,之后逐步被工业控制、汽车电子、通信和消费电子领域广泛使用。与此同时,各种新兴的应用也对嵌入式系统的处理能力、通信能力等方面提出了更高的要求。

    S3C4510B 正是 Samsung 公司针对新兴网络应用而开发的一款性价比很高的 ARM 核 16/32 位RISC 微处理器。它内含一个由 ARM 公司设计的高性能、低功耗的 ARM7TDMI 内核,内置 10/100M Ethernet 控制器、HDLC 控制器等一系列网络通信控制器,特别适合对价格和功耗均比较敏感的嵌入式网络应用。

    uClinux 是针对通信和控制领域的嵌入式操作系统,其主要的优势在于开放源代码、稳定、强大的网络通信功能以及其精简性。其内核功能与 Linux 基本相同,只是对内存管理和进程管理进行了改写,主要应用于没有 MMU 的微处理器平台,如 S3C4510B 处理器。

    本文根据笔者在实际工作中积累的经验,对 uClinux 在S3C4510B上的移植和开发进行了较为详细的介绍。本文首先介绍了如何将 uClinux 移植到 S3C4510B 嵌入式平台,接下来将分别对 uClinux 在 S3C4510B 平台上的各种网络服务设置、驱动及用户程序开发进行详细的论述。

移植 uClinux 至 S3C4510B 平台

   Uclinux 的内核现已发展至 2.6 版本。然而,考虑到嵌入式应用大多针对特定需求,开发者往往更关注诸如能耗、空间占用、开发速度、向后兼容等问题,因而在实际开发中 2.4 和 2.6 版本的 uClinux 都会根据项目情况被采用。根据笔者在实际工作中的经验,本文下面将对 2.4 和 2.6 版本的 uClinux 移植到 S3C4510B 嵌入式平台的方法分别进行介绍。

UClinux 2.4 的移植

Step 1:下载内核压缩包和交叉编译工具包

笔者使用的是分别是:uClinux-dist-20030522.tar.gz 和 arm-elf-tools-20030314.sh。将内核压缩包解压至开发主机,然后安装 arm-linux 交叉编译工具,为后续的编译做好准备。

Step 2:修改 Makefile 文件

../linux-2.4.x/Makefile
# normal make targets下面的Section加入:

.PHONY: images
images:
$(MAKE) -C $(VENDDIR) images
all: subdirs romfs modules modules_install image

上述语句将在make image的时候生成压缩的映像文件(image)。

../linux-2.4.x/vendors/Samsung/4510B/Makefile
首先,找到语句

genromfs -v -V "ROMdisk" -f $(ROMFSIMG) -d $(ROMFSDIR)

在其下方加入:

arm-elf-ld -r -o $(ROOTDIR)/$(LINUXDIR)/romfs.o \
-b binary $(ROMFSIMG)

此语句的作用是产生 romfs.o 供后续生成整体的映像文件使用。

同时,在此 Makefile 的最后加入:

images:
arm-elf-objcopy -O binary -R .note -R .comment -S $(ROOTDIR)/$(LINUXDIR)/linux \
$(IMAGEDIR)/uclinux_ram.bin
cp $(ROOTDIR)/$(LINUXDIR)/arch/armnommu/boot/zImage \
$(IMAGEDIR)/uclinux_rom.bin

    上述语句将在交叉编译的最后将所有生成的目标文件 Dump 到可以下载到开发板中的映像文件中(注意,这里提供两种形式:ROM 启动的 uclinux_rom.bin 和 RAM 启动的 uclinux_ram.bin)

../linux-2.4.x /arch/armnommu/boot/compressed/Makefile
将此文件中的下列语句:

$(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o -o $(LINUX)

修改为:

$(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(LIBGCC) -o $(LINUX)

此语句将 arm-elf-tools 库的 libgcc 链接入 uClinux 的 kernel 中。

Step 3:配置操作系统地址转换

由于 S3C4510B 不含 MMU (Memory Management Unit), 因此其物理地址和虚拟地址是相同的。在../linux-2.4.x/include/asm/mmu.h 中需要加入下列代码以完成此转换:
#define __virt_to_phys__is_a_macro
#define __virt_to_phys(vpage) ((unsigned long) (vpage))
#define __phys_to_virt__is_a_macro
#define __phys_to_virt(ppage) ((void *) (ppage))

#define __virt_to_bus__is_a_macro
#define __virt_to_bus(vpage) ((unsigned long) (vpage))
#define __bus_to_virt__is_a_macro
#define __bus_to_virt(ppage) ((void *) (ppage))

Step 4:配置romfs

由于uClinux缺省使用romfs作为根文件系统,因此需要对此进行配置:

../linux-2.4.x/arch/armnommu/vmlinux-armv.lds.in
*(.got) /* Global offset table */语句后加入下列语句,从而将上文Step 2 (2) 中生成的romfs.o包含到.text段中:

romfs_data = .;
romfs.o
romfs_data_end = .;

../linux-2.4.x /drivers/block/blkmem.c
此文件是romfs的配置文件,找到“arena[] = {”语句,在其花括号中加入下列3行:

#ifdef CONFIG_ARCH_SAMSUNG
{0, romfs_data, -1},
#endif

Step 5:其他修改

../linux-2.4.x/arch/armnommu/mm/proc-arm6,7.S
此文件中有一个错误语句:

mov r0, #0
#ifdef CONFIG_CPU_WITH_CACHE

将其修改为:

#ifdef CONFIG_CPU_WITH_CACHE
mov r0, #0

至此,经过修改的uClinux内核已经可以在开发主机上使用make dep, make lib_only, make user_only, make romfs, make image和make 生成 uclinux_rom.bin 和uclinux_ram.bin 映像文件 并在开发板上顺利运行至uClinux欢迎界面和等待命令输入提示符。需要注意的是, uclinux_ram.bin是压缩过的内核映像,可以使用调试器直接烧写至SDRAM中运行,而 uclinux_rom.bin是没有压缩过的内核映像,需要烧写入FLASH中运行。因此,在调试过程中,一般将待调试的内核映像uclinux_ram.bin通过调试器或Bootlaoder(Redboot等)写入SDRAM中进行调试,待完全调试好之后再将最终uclinux_rom.bin版本烧写入FLASH中固化。

uClinux 2.6的移植

Step 1:下载内核压缩包和交叉编译工具包

对于2.6内核的uClinux,需要下载uClinux-dist-20051014.tar.gz内核压缩包以及Linux 2.6版本内核及补丁:linux-2.6.9.tar.bz2、linux-2.6.9-hsc0.patch.gz;同时还需要下载交叉编译工具并进行安装:arm-uclinux-tools-base-gcc3.4.0-20040713.sh。

Step 2:为uClinux更新标准Linux 2.6版本内核

执行下列命令将uClinux-dist-20051014的内核替换为标准Linux的2.6内核:

tar -zxvf uClinux-dist-20051014.tar.gz
cp linux-2.6.9.tar.bz2 uCliux-dist
cd uClinux-dist
tar –xjvf linux-2.6.9.tar.bz2
gzip -dc ../linux-2.6.9-hsc0.patch.gz | patch -p0
rm -rf linux-2.6.x
mv linux-2.6.9 linux-2.6.x

Step 3:配置内核中S3C4510B的参数设置

由于Step 2 中的补丁并没有包括专门针对S3C4510B的内核配置,因此我们只能使用现有的 espd-4510的内核配置文件:

$cp ../linux-2.6.x/arch/armnommu/configs/espd_4510b_defconfig \
../linux-2.6.x/vendor/Samsung/4510B/config.linux-2.6.x

同时,由于没有特别针对Linux 2.6内核的S3C4510B vendor配置文件因此只能使用现有2.4版本 的vendor配置文件:

$cp ../linux-2.6.x/vendor/Samsung/4510B/config.vendor-2.4.x \
 ../linux-2.6.x/vendor/Samsung/4510B/config.vendor-2.6.x

Step 4:修改Makefile文件

../linux-2.6.x/vendor/Samsung/4510B/Makefile
由于现有的Makefile当中并没有包含编译可烧写至嵌入式存储系统中的映像文件的相应命令,因此需要在此Makefile中添加:
image:
[ -d $(IMAGEDIR) ] || mkdir -p $(IMAGEDIR)
genromfs -v -V "ROMdisk" -f $(ROMFSIMG) -d $(ROMFSDIR)

arm-uclinux-ld -r -o $(ROOTDIR)/$(LINUXDIR)/romfs.o -b binary $(ROMFSIMG)
$(CROSS_COMPILE)objcopy -O binary --remove-section=.romvec \
--remove-section=.text --remove-section=.ramvec \
--remove-section=.init \
--remove-section=.bss --remove-section=.eram
$(ROOTDIR)/$(LINUXDIR)/linux $(IMAGEDIR)/linux.data

Step 5:配置romfs

与移植uClinux 2.4内核相同,需要修改下列文件以对romfs进行支持:

../linux-2.6.x/arch/armnommu/vmlinux-armv.lds.in
*(.got) /* Global offset table */语句后加入下列语句,从而romfs.o包含到.text段中。

romfs_data = .;
romfs.o
romfs_data_end = .;

../linux-2.6.x/arch/armnommu/kernel/setup.c
添加变量romfs_start和romfs_end:

extern int _stext, _text, _etext, _edata, _end;
extern int romfs_start,romfs_end;

同时,对内核启动时的default command line进行设置:

char *from = default_command_line;
sprintf(default_command_line, "root=/dev/ram0 initrd=0x%08lx", \
(unsigned long)&romfs_start);

至此,uClinux 2.6版本的内核移植完成,可以通过make dep, make lib_only, make user_only, make romfs, make image和make编译出可以烧写入SDRAM或FLASH的内核映像文件。

S3C4510B嵌入式平台主要网络服务配置

   在嵌入式开发和调试中,最常用的网络服务是使用Telnet登录嵌入式开发板以及使用NFS文件系统。本文下面将根据笔者的实际经验对uClinux 2.4环境下这些网络服务的配置进行说明。

uClinux中Telnet服务器的配置

   由于Telnet使用串口建立终端进行通信,因此为了在嵌入式开发板上架设Telnet服务器,首先需要修改uClinux的内核配置。具体来说,需要在make menuconfig时进行下列配置:

在Character devices选项页中,将Virtual Terminal和Support for console on virtual terminal两个选项都选中,从而在内核中添加对Telnet所需的虚拟终端的支持。
在Custom Vendor/Product ? Network Application选项页中,需要将telnet, telnetd以及inetd都选中
在Custom Vendor/Product ? Tinylogin选项页中,需要将login, Passwd和getty都选中。
在Custom Vendor/Product ? Miscellaneous Application选项页中,确认Login没有被选中,因为我们希望使用Tinylogin提供的Login功能。
由于在上面的内核配置中选择了对虚拟终端的支持,因此需要手动在../linux-2.4-x/.config中加入CONFIG_DUMMY_KEYB=y,否则编译时会出现编译错误。

同时,由于uClinux内核自身的问题,按照上述方式配置的Telnet在连接时总是出现login用户名和密码验证错误的问题。此问题可以通过修改../linux-2.4-x/user/tinylogin/login.c,省略Telnet连接时的用户名/密码验证来解决:

extern int login_main(int argc, char **argv)
{
    char name[32];
    char tty[BUFSIZ];


#ifdef TLG_FEATURE_SHADOWPASSWDS
    struct spwd *spwd = NULL;
#endif    /* TLG_FEATURE_SHADOWPASSWDS */
    char **envp = environ;

    initenv();
/* bypass username/password auth process. Directly start Sash Shell */
    shell("/bin/sh", (char *) 0);    /* exec the shell finally. */
    return (0);
}

重新编译按照上述方法进行修改的内核并将编译好的映像文件烧写入FLASH,系统上电启动后完成后运行:

/bin> inetd &

开发人员便可以通过Telnet访问嵌入式开发板了。

uClinux中NFS的配置

   为了在S3C4510B嵌入式开发板上使用NFS文件系统,需要按照如下的方法修改uClinux内核:运行内核配置程序make menuconfig,选中Customized Kernel Settings和Customized Vendor/User Settings,然后在接下来的配置中按照如下方式进行设置:

Customized Kernel Settings ? File systems选项页中
选中NFS file system support和Provide NFSv3 client support。

Customized Vendor/User Settings ? Network Application选项页中
选中portmap,提供端口映射功能。

Customized Vendor/User Settings ? BusyBox选项页中
选中mount和mount: support NFS mounts。

    完成上述配置之后,重新编译内核,新内核便可提供NFS Server和Client的支持。在通常情况下, 一般会使用S3C4510B嵌入式开发板作为NFS Client,而开发主机作为NFS Server。例如,开发主机(192.168.0.8)通过配置/etc/exports文件已将/nfs_mount目录设置为NFS目录,则在 S3C4510B嵌入式开发板即可通过下列命令将开发主机的NFS目录挂载至本地/var目录:

/bin > portmap &
/bin > mount 192.168.0.8:/nfs_mount /var

S3C4510B嵌入式平台驱动程序开发

   uClinux目前并不支持使用insmod动态加载驱动程序,因此S3C4510B嵌入式平台上的驱动程序都需要编译进入内核在启动时自动加载。下面分别对S3C4510B嵌入式平台上的字符驱动程序和网络驱动程序的开发进行一些论述。

uClinux中字符驱动程序的开发

开发人员在编写完所需的字符类型驱动程序之后,需要将驱动程序源代码置于
../linux-2.4.x/driver/char目录下,同时修改同级目录下的Makefile。例如,笔者完成了一个S3C4510B的LCD驱动程序(lcd.c),则需要将lcd.c置于../linux-2.4.x/driver/char目录,同时在../linux-2.4.x/driver/char/Makefile中加入:

obj_y += lcd.o

同时,为了能够在uClinux启动时自动初始化此设备,还需要修改../linux-2.4.x/driver/char/mem.c文件,在其中加入:

新添加的字符驱动程序初始化函数声明。例如:
extern void lcd_init(void);

在字符设备统一初始化函数int __init chr_dev_init(void)中调用新设备的初始化函数。例如上面提到的LCD的例子,需要在函数int __init chr_dev_init(void)中加入语句:
lcd_init();

函数int __init chr_dev_init(void)中,字符设备的初始化函数将统一被调用,并完成各个字符驱动file_operations数据结构的注册。初始化好之后就可以使用这些字符设备了。

uClinux中网络驱动程序的开发

在uClinux中加入网络驱动设备比较简单,只需将编写好的网络驱动程序置于../linux-2.4.x/driver/net,再修改../linux-2.4.x/driver/net/Makefile即可。例如,笔者编写了HDLC的驱动程序
s3c4510b_hdlc.c,只需将其置于../linux-2.4.x/driver/net目录下,然后修改../linux-2.4.x/driver/net/Makefile,在其中加入:

obj-y += s3c4510b_hdlc.o

uClinux执行make时会根据此Makefile产生新的驱动模块,并将其链接入net.o,系统启动时将会统一加载所有的网络驱动程序。

uClinux特殊网络设备驱动程序开发

由于嵌入式应用中往往会对网络应用有特别的需求,因而需要在嵌入式开发板中支持一些不太常用的网络设备(如HDLC设备等)。对此感兴趣的读者可以参考笔者的另外一篇论文《基于 S3C4510B 和 uClinux 的 HDLC 接口的设计与实现》。

S3C4510B嵌入式平台用户空间程序开发

除了驱动程序,开发人员还需要在S3C4510B嵌入式平台上进行用户空间应用程序的开发,具体步骤如下:

Step 1:在../linux-2.4.x/user目录中为应用程序建立相应目录树结构

例如,笔者在开发中需要开发一个在S3C4510B自带的LCD上显示消息的用户程序(write_lcd.c),则首先需要在../linux-2.4.x/user下新建一个目录(如lcd),然后将应用程序置于此目录下
../linux-2.4.x/user/lcd/write_lcd.c)。

Step 2:修改2级Makefile文件

../linux-2.4.x/user/Makefile
由于在../linux-2.4.x/user目录下加入了新的目录树结构,因此需要修改../linux-2.4.x/user/Makefile文件,使运行make时能够进入新目录进行编译。在上面的例子中,需要在
../linux-2.4.x/user/Makefile中加入:

dir_y += lcd

以指示系统在编译时进入lcd目录。

../linux-2.4.x/user/lcd/Makefile
新建目录中必须提供一个Makefile供make时使用,下面是笔者在实际开发中使用的此处Makefile模板,不同的应用程序只需更改模板中的EXEC和OBJS宏即可:

EXEC = write_lcd
OBJS = write_lcd.o
CFLAGS += -I.

all: $(EXEC)

$(EXEC): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
romfs:
    $(ROMFSINST) /bin/$(EXEC)
clean:
    -rm -f $(EXEC) *.elf *.gdb *.o

完成上述步骤之后,运行make user_only编译命令时,将会对../linux-2.4.x/user/目录下的用户程序进行编译,并将编译出的可执行文件置于romfs中的bin目录下。

小结

本文根据笔者在实际工作中的经验,对uClinux在S3C4510B嵌入式平台上的移植和开发等主题进行了总结。本文给出了移植uClinux 2.4和2.6版本至S3C4510B平台、配置常用网络服务、各种驱动程序以及用户程序开发的详细步骤,相信能够帮助进行类似工作的开发人员加快开发速度;同时,也能够对开发其他类型的嵌入式系统提供有益的借鉴。

参考资料
http://
刘朋, 金野.《 基于 S3C4510B 和 uClinux 的 HDLC 接口的设计与现》 ,微计算机信息,2007 Vol. 23 No.5 pp. 1—3
Alessandro Rubini, Jonathan Corbet. Linux Device Driver. 北京:中国电力出版社

关于作者
  刘朋,男,云南昆明人,北京大学“通信与信息系统”硕士。现供职于IBM中国开发中心,主要研究兴趣为无线网络通信协议、Linux 嵌入式系统以及HPC(High Performance Computing)。
 
 


阅读(1171) | 评论(0) | 转发(0) |
0

上一篇:mkdir()函数

下一篇:strip 命令

给主人留下些什么吧!~~