39
1 建建建建建 Linux 建建建

建立嵌入式 Linux 应用系统

  • Upload
    bat

  • View
    110

  • Download
    0

Embed Size (px)

DESCRIPTION

建立嵌入式 Linux 应用系统. 概要. 开发环境 内核配置 bootloader 根文件系统 系统配置和管理 应用开发. 主机系统和目标机系统 主机: x86 , sparc , ... 开发板,评估板,用户定制系统 嵌入式微处理器使用的体系结构 x86 , arm , ppc , mips , ... 主机操作系统 Unix/Linux 交叉编译工具链 编译器,二进制工具集, Windows 专用集成开发环境 如: ADS ,用于编译 ARM 体系结构的代码 虚拟机 VMware+Linux. 其它 内核或驱动程序开发 内核源代码 - PowerPoint PPT Presentation

Citation preview

Page 1: 建立嵌入式 Linux 应用系统

1

建立嵌入式 Linux应用系统

Page 2: 建立嵌入式 Linux 应用系统

2

概要• 开发环境• 内核配置• bootloader

• 根文件系统• 系统配置和管理• 应用开发

Page 3: 建立嵌入式 Linux 应用系统

3

开发环境• 主机系统和目标机系统

– 主机: x86 , sparc , ...– 开发板,评估板,用户定制系统

• 嵌入式微处理器使用的体系结构– x86 , arm , ppc , mips , ...

• 主机操作系统– Unix/Linux

• 交叉编译工具链– 编译器,二进制工具集,

– Windows• 专用集成开发环境

– 如: ADS,用于编译 ARM体系结构的代码

• 虚拟机– VMware+Linux

• 其它– 内核或驱动程序开发

• 内核源代码– 应用程序开发

• 交叉编译工具集相关头文件和库函数

Page 4: 建立嵌入式 Linux 应用系统

4

交叉编译工具集• 交叉编译器

– gcc:编译器,将 c程序转换成汇编程序– as:汇编器,将汇编程序转换成目标代码

• 二进制工具 (binutil)– ld:连接器,将 (多个 )目标代码连接成一个目标代码或可执行代码– nm:用于读取目标代码中的符号– objcopy:可以将一种目标代码形式转换成另一种目标代码形式– objdump:反汇编一个目标代码或可执行代码– strip:从目标代码中去掉符号表– ...

• c库– 静态库: libc.a , libm.a , ...– 动态库: libc.so , libm.so , ld.so , ...

Page 5: 建立嵌入式 Linux 应用系统

5

获得交叉编译工具集• GNU提供编译工具的源代码,用户可以自己建立交叉编译工具集。– 需要的源代码 (可从 GNU提供的众多镜像网站上得到 )

• gcc:编译器• binutils:二进制工具• kernel:内核• gdb:调试器• glibc : c库

• 通常可以找到预编译好的交叉编译工具集– 编译器版本与内核版本有一定的关联

• 大多来源于经验,无确定对应关系。– 如: ARM体系结构的交叉编译工具集

• http://handhelds.org/download/projects/toolchain/arm-linux-gcc-3.4.1.tar.bz2

Page 6: 建立嵌入式 Linux 应用系统

6

内核编译配置• 预置选项

– 可用命令• make config• make menuconfig• make xconfig

• 新增功能或模块– 增加预置选项

• arch/$(ARCH)/config.in

– 直接修改相关Makefile文件

Page 7: 建立嵌入式 Linux 应用系统

7make menuconfig

Page 8: 建立嵌入式 Linux 应用系统

8make menuconfig

Page 9: 建立嵌入式 Linux 应用系统

9make menuconfig

Page 10: 建立嵌入式 Linux 应用系统

10

例 1:内核编译主要配置选项• Loadable module support

– Enable loadable module support• Kernel module loader

• System type– (S3C2410-based) ARM system type– SMDK (MERI TECH BOARD)

• change AIJI• by threewater--1

– ARM920T CPU idle– ARM920T I-Cache on– ARM920T D-Cache on

• General setup– (0) Compressed ROM boot loader base address– (0) Compressed ROM boot loader RSS address– Networking support– System V IPC– Sysctl support– NWFPE math emulation– (ELF) Kernel core (/proc/kcore) format– Kernel support for ELF binaries– Kernel-mode alignment trap handler

• Networking options– Packet socket

• Packet socket: mmapped IO– Unix domain sockets– TCP/IP networking

• IP: multicasting

• Character devices– Virtual terminal– Unix98 PTY support– S3C2410 Real Time Clock

• File systems– Kernel automounter version 4 support– Yaffs filesystem on NAND– Compressed ROM file system support– /proc file system support– /dev file system support

• Automatically mount at boot– /dev/pts file system for Unix98 PTYs– Network File Systems

• NFS file system support– Provide NFSv3 client support

Page 11: 建立嵌入式 Linux 应用系统

11

bootloader

• bootloader:引导加载程序– boot loader , bootstrap loader , bootstrap , ...– 可能由多个程序接力完成引导加载过程– 作用

• 只负责系统的启动引导• 作为系统监控程序

• 各种 Linux系统用 bootloader– lilo– GRUB– u-boot– vivi– redboot

Page 12: 建立嵌入式 Linux 应用系统

12

vivi

• vivi是由韩国 mizi公司设计为 ARM处理器系列设计的一个 bootloader– http://www.mizi.com

• vivi目前只支持使用串口和主机通信,所以必须使用一条串口电缆来连接目标板和主机。

– vivi最初的加载需要使用 JTAG端口• 主要功能

– flash管理和读写– 串口数据传输– 硬件初始化– 启动内核

• 内置命令– load:通过串口进行数据传输– part:将 flash进行分区– param:显示和设置各种参数– boot:启动各种应用,包括 Linux内核– flash:管理 flash设备

Page 13: 建立嵌入式 Linux 应用系统

13

编译 vivi

配置:make config 或make menuconfig

编译:make 或make vivi

Page 14: 建立嵌入式 Linux 应用系统

14

vivi> bon part 0 128k 192k 1216k 4288k:m 64704k

mtd_partition_t default_mtd_partitions[] = {{

name: "vivi",offset: 0,size: 0x00020000,flag: 0

}, {name: "param",offset: 0x00020000,size: 0x00010000,flag: 0

}, {name: "kernel",offset: 0x00030000,size: 0x000C0000,flag: 0

}, {name: "root",offset: 0x00100000,size: 0x00140000,flag: MF_BONFS

}};

128k 64k 1024k 3072k 60416k

vivi/arch/s3c2410/smdk.c

vivi param kernel root yaffs

Page 15: 建立嵌入式 Linux 应用系统

15

u-boot

• 由 DENX Software Engineering提供的引导加载程序,可支持多种微处理器。– http://www.denx.de– arm, mips, i386, ppc, ...

• u-boot提供多种功能– flash以及 SDRAM的管理和读写– 串口数据传输– 加载和启动内核或其它应用程序– 支持网络启动– 识别多种文件系统

• 内置命令– 内置命令非常多,用户可根据需要进行裁减或添加。

Page 16: 建立嵌入式 Linux 应用系统

16

cpu/$(CPU)/start.Su-boot 的启动部分代码为汇编程序

...

intdo_version (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){

extern char version_string[];printf ("\n%s\n", version_string);return 0;

}

U_BOOT_CMD(version, 1, 1, do_version,"version - print monitor version\n",NULL

);

...

u-boot-$(version)/common/command.c

u-boot 命令实现

Page 17: 建立嵌入式 Linux 应用系统

17

编译 u-boot

配置: ( 例: s3c2410)make smdk2410_config

编译:make 或make u-boot.bin

Page 18: 建立嵌入式 Linux 应用系统

18

根文件系统• Linux系统运行需要根文件系统

– 根节点– 文件系统

• 常用根文件系统– cramfs– romfs– ramdisk

• ext2– 其它

• 基于磁盘• yaffs , ...

Page 19: 建立嵌入式 Linux 应用系统

19

根文件系统内容drwxr-xr-x 2 root root 1024 Dec 2 2006 bindrwxr-xr-x 3 root root 2048 Mar 20 2006 devdrwxr-xr-x 6 root root 1024 Dec 2 2006 etcdrwxr-xr-x 2 root root 1024 Jul 5 2004 homedrwxr-xr-x 2 root root 1024 Jul 5 2004 libdrwxr-xr-x 3 root root 1024 Dec 2 2006 mntdrwxr-xr-x 2 root root 1024 Apr 4 2000 procdrwxr-x--- 2 root root 1024 Mar 20 2006 rootdrwxr-xr-x 2 root root 1024 Feb 5 2003 sbindrwxrwxrwt 2 root root 1024 Apr 4 2000 tmpdrwxr-xr-x 7 root root 1024 Jul 5 2004 usrdrwxr-xr-x 8 root root 1024 Apr 18 2003 var

Page 20: 建立嵌入式 Linux 应用系统

20

lrwxrwxrwx 1 501 root 7 Apr 21 10:10 ash -> busybox-rwxr-xr-x 1 501 root 385516 Apr 21 10:10 busyboxlrwxrwxrwx 1 501 root 7 Apr 21 10:10 cat -> busyboxlrwxrwxrwx 1 501 root 7 Apr 21 10:10 chgrp -> busyboxlrwxrwxrwx 1 501 root 7 Apr 21 10:10 chmod -> busyboxlrwxrwxrwx 1 501 root 7 Jan 1 1970 chown -> busyboxlrwxrwxrwx 1 501 root 7 Jan 1 1970 cp -> busyboxlrwxrwxrwx 1 501 root 7 Jan 1 1970 date -> busyboxlrwxrwxrwx 1 501 root 7 Jan 1 1970 dd -> busybox

/bin

-rwxr-xr-x 1 501 root 14180 Apr 21 10:19 cardctl-rwxr-xr-x 1 501 root 44368 Apr 21 10:19 cardmgr-rwxr-xr-x 1 501 root 54476 Apr 21 10:19 depmod-rwxr-xr-x 1 501 root 82172 Apr 21 10:19 fdisklrwxrwxrwx 1 501 root 14 Jan 1 1970 freeramdisk -> ../bin/busybox-rwxr-xr-x 1 501 root 53572 Jan 1 1970 ftpd-rwxr-xr-x 1 501 root 11880 Jan 1 1970 fuserlrwxrwxrwx 1 501 root 14 Jan 1 1970 getty -> ../bin/busyboxlrwxrwxrwx 1 501 root 14 Jan 1 1970 halt -> ../bin/busybox-rwxr-xr-x 1 root root 41781 Jan 1 1970 hciconfig-rwxr-xr-x 1 root root 61572 Jan 1 1970 hcid-rwxr-xr-x 1 root root 41502 Jan 1 1970 hcitool-rwxr-xr-x 1 501 root 1818 Jan 1 1970 hotpluglrwxrwxrwx 1 501 root 14 Jan 1 1970 ifconfig -> ../bin/busybox

/sbin

Page 21: 建立嵌入式 Linux 应用系统

21

lrwxrwxrwx 1 501 root 17 Apr 21 10:27 [ -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Apr 21 10:27 basename -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Apr 21 10:27 bunzip2 -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Apr 21 10:27 bzcat -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Jan 1 1970 chvt -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Jan 1 1970 clear -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Jan 1 1970 cmp -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Jan 1 1970 cut -> ../../bin/busyboxlrwxrwxrwx 1 501 root 17 Jan 1 1970 deallocvt -> ../../bin/busybox

/usr/bin

lrwxrwxrwx 1 501 root 17 Apr 21 10:34 chroot -> ../../bin/busybox-rwxr-xr-x 1 root 232 4092 Apr 21 10:34 dongle_attach-rwxr-xr-x 1 root root 17332 Apr 21 10:34 imagewrite-rwxr-xr-x 1 501 root 9164 Apr 21 10:34 imagewrite5-rwxr-xr-x 1 root 232 11916 Jan 1 1970 irattach-rwxr-xr-x 1 root root 9726 Jan 1 1970 irdaping-rwxr-xr-x 1 root root 6437 Jan 1 1970 irnetd

/usr/sbin

Page 22: 建立嵌入式 Linux 应用系统

22

ramdisk

• 内核支持– CONFIG_BLK_DEV_INITRD=y– drivers/block/rd.c

• 使用– 只在系统启动过程中使用

• 加载额外的设备驱动程序等– 作为系统根文件系统

• 制作– 见:文件系统和网络系统,例 1。– 将根文件系统内容拷贝到 ramdisk中。

Page 23: 建立嵌入式 Linux 应用系统

23

cramfs

• 内核支持– CONFIG_CRAMFS=y– fs/cramfs

• 使用– 只读文件系统– 通常作为嵌入式系统的根文件系统

• 特点– 文件大小不能超过 16MB– 文件系统大小最大只有 256MB(可以稍微超过一点 )– 只能使用 4096字节大的磁盘块– 字节顺序与制作主机使用的字节顺序相同

• 制作– 工具: mkcranfs , cramfsck

• http://sourceforge.net/projects/cramfs/

Page 24: 建立嵌入式 Linux 应用系统

24

busybox

• 专门为嵌入式系统或其它袖珍型系统开发的多功能系统工具,常被称为嵌入式系统上的瑞士军刀。– http://www.busybox.net– 可实现大多数常用 unix 或 linux命令

• 符合 unix命令使用习惯• 特性

– 用一个可执行文件实现多种命令功能– 针对嵌入式系统的应用

• 尽量小的代码尺寸• 去掉不常用的命令选项

– 用户可根据需要配置和裁剪 busybox– 有很好的可移植性

Page 25: 建立嵌入式 Linux 应用系统

25

使用 busybox命令

Busybox 将 unix命令作为参数,进而执行相应功能。如:$ busybox ls -l /proc

为符合 unix命令的使用习惯,通常将 unix命令作为符号链接指向 busybox。这时可以直接使用符号链接形式的命令直接调用 busubox。

Page 26: 建立嵌入式 Linux 应用系统

26

配置和编译 busybox$ make menuconfig

Page 27: 建立嵌入式 Linux 应用系统

27

busybox命令实现

struct BB_applet { const char *name; int (*main) (int argc, char **argv); enum Location location:4; enum SUIDRoot need_suid:4;};

include/busybox.h: struct BB_applet

busybox中把每个命令称为一个 applet,并用一个 BB_applet 类型的数据结构表示。

Page 28: 建立嵌入式 Linux 应用系统

28

const struct BB_applet applets[] = { #define APPLET(a,b,c,d) {#a,b,c,d}, #define APPLET_NOUSAGE(a,b,c,d) {a,b,c,d}, #define APPLET_ODDNAME(a,b,c,d,e) {a,b,c,d},

#ifdef CONFIG_TEST APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)#endif#ifdef CONFIG_ADDGROUP APPLET(addgroup, addgroup_main, _BB_DIR_BIN, _BB_SUID_NEVER)#endif#ifdef CONFIG_ADDUSER APPLET(adduser, adduser_main, _BB_DIR_BIN, _BB_SUID_NEVER)#endif...};

include/applets.h: applets[ ]

所有配置时选中的命令保存在 applets数组中,数组中的元素为BB_applet 类型的数据结构。

Page 29: 建立嵌入式 Linux 应用系统

29

int main(int argc, char **argv){

const char *s;

bb_applet_name = argv[0];

if (bb_applet_name[0] == '-')bb_applet_name++;

for (s = bb_applet_name; *s != '\0';) {if (*s++ == '/')

bb_applet_name = s;}

run_applet_by_name(bb_applet_name, argc, argv);bb_error_msg_and_die("applet not found");

}

applets/busybox.c: main( )

busybox 的 main函数

Page 30: 建立嵌入式 Linux 应用系统

30

void run_applet_by_name (const char *name, int argc, char **argv){ static int recurse_level = 0; extern int been_there_done_that; /* From busybox.c */ ... /* Do a binary search to find the applet entry given the name. */ if ((applet_using = find_applet_by_name (name)) != NULL) { bb_applet_name = applet_using->name; if (argv[1] && strcmp (argv[1], "--help") == 0) { if (strcmp (applet_using->name, "busybox") == 0) { if (argv[2]) applet_using = find_applet_by_name (argv[2]); else applet_using = NULL; } if (applet_using) bb_show_usage ();

been_there_done_that = 1; busybox_main (0, NULL); } exit ((*(applet_using->main)) (argc, argv)); } ...}

applets/applet.c: run_applet_by_name( )

run_applet_by_name( )

Page 31: 建立嵌入式 Linux 应用系统

31

系统配置和管理内核启动 init进程

static int init(void * unused){

lock_kernel();...unlock_kernel();.../* * We try each of these until one succeeds. * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */if (execute_command)

execve(execute_command,argv_init,envp_init);execve("/sbin/init",argv_init,envp_init);execve("/etc/init",argv_init,envp_init);execve("/bin/init",argv_init,envp_init);execve("/bin/sh",argv_init,envp_init);panic("No init found. Try passing init= option to kernel.");

}

init/main.c: init( )

linuxrc

Page 32: 建立嵌入式 Linux 应用系统

32

/sbin/init程序执行过程系统的 init程序根据配置文件 /etc/inittab配置操作系统并进而启动各种系统级应用。用户可通过修改配置文件 inittab改变系统启动参数。

# Default runlevel. The runlevels used by RHS are:# 0 - halt (Do NOT set initdefault to this)# 1 - Single user mode# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)# 3 - Full multiuser mode# 4 - unused# 5 - X11# 6 - reboot (Do NOT set initdefault to this)# id:3:initdefault:

# System initialization.si::sysinit:/etc/rc.d/rc.sysinit

l0:0:wait:/etc/rc.d/rc 0l1:1:wait:/etc/rc.d/rc 1l2:2:wait:/etc/rc.d/rc 2l3:3:wait:/etc/rc.d/rc 3l4:4:wait:/etc/rc.d/rc 4l5:5:wait:/etc/rc.d/rc 5l6:6:wait:/etc/rc.d/rc 6...

/etc/inittab

Page 33: 建立嵌入式 Linux 应用系统

33

rc.sysinit

rc.sysinit是一个 shell 脚本,负责启动各种基本系统功能:将启动过程记入系统日志启动网络功能启动控制台,设定字体加载 /proc文件系统设定内核参数设置时钟设置主机名加载各种模块加载各种磁盘文件系统启动网络系统根据系统运行级别启动相应的服务器程序

/etc/rc.d/rc0.d~rc6.d用户可使用 chkconfig命令配置服务器启动选项

Page 34: 建立嵌入式 Linux 应用系统

34

rc.localrc.local 也是一个 shell 脚本,主要用于用户启动各种用户自己设定的启动程序或命令,这些程序或命令在系统启动时将会被自动执行。 rc.local在所有其它初始化脚本执行完后才执行。

#!/bin/sh## This script will be executed *after* all the other init scripts.# You can put your own initialization stuff in here if you don't# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

# added by liyi/sbin/ifconfig eth0 192.168.1.12

例: rc.local

Page 35: 建立嵌入式 Linux 应用系统

35

重要系统配置文件• /etc/inittab• /etc/fstab• /etc/resolv.conf• /etc/xinetd.d/*• /etc/securetty• /etc/logrotate.conf• /etc/hosts, hosts.allow, hosts.deny• /etc/exports• /etc/security/*• /etc/X11/XF86Config• /etc/sysconfig/*

Page 36: 建立嵌入式 Linux 应用系统

36

例 2 : rc3.dK05saslauthd K36lisa S05kudzu S17keytable S56rawdevices S95atdK15httpd K45named S08iptables S20random S56xinetd S97rhnsdK20nfs K50snmpd S09isdn S24pcmcia S85gpm S99localK24irda K50snmptrapd S10network S25netfs S90crondK30sendmail K50vsftpd S12syslog S26apmd S90cupsK35smb K74ntpd S13portmap S28autofs S90xfsK35winbind K95firstboot S14nfslock S55sshd S95anacron

S99local -> ../rc.local...K15httpd -> ../init.d/httpd

S dd name S: start ,系统启动时执行的脚本 dd: 00-99 ,数值小则先被系统执行 name: init.d 目录中对应的脚本名称

K dd name K: kill ,系统退出时执行的脚本 dd: 00-99 ,数值小则先被系统执行 name: init.d 目录中对应的脚本名称

Page 37: 建立嵌入式 Linux 应用系统

37

应用程序开发和调试• 程序编译

– 交叉编译环境– 使用静态连接还是动态连接库

• 应用程序调试– 基于 Linux系统的调试方法

• gdb• gdbserver• http://www.gnu.org

– 其它调试方法• JTAG , ...

Page 38: 建立嵌入式 Linux 应用系统

38

使用 gdb 和 gdbserver调试程序

192.168.1.10主机gdb

192.168.1.12目标机

gdbserver

网络 / 串口

# gdbserver 192.168.1.10:4567 myprogProcess myprog created; pid = 678Remote debugging from host 192.168.1.10Killing inferior#

$ gdbGNU gdb Red Hat Linux ...(gdb) target remote 192.168.1.12:4567Remote debugging using 192.168.1.12:45670x40000be0 in ?? ()(gdb) 运行各种调试命令(gdb)q$

Page 39: 建立嵌入式 Linux 应用系统

39

关于考试• 50分• 范围

– 内存:管理,寻址– 进程:基本概念,创建,调度, ...– 中断、定时、系统调用:基本概念– 文件系统: ext2文件系统,基本概念,结构– 设备驱动程序:基本概念,结构, ...