1、第二章 嵌入式Linux内核文件 系统与存储,第二章 嵌入式Linux内核文件 系统与存储,主要内容第一节 Linux内核定制、裁剪和添加 第二节 嵌入式引导系统(BootLoader)技术 第三节 文件系统的构建,学习方法与建议,本章主要介绍了三个部分,分别是嵌入式linux内核、引导系统介绍和文件系统等相关内容。该章节详细介绍了关于嵌入式系统如何构建以及内核部分的应用操作等内容,可以更好的帮助理解嵌入式系统的相关内容,具有一定的应用价值。,1,一、概述 二、内核目录介绍 三、配置文件和配置工具 四、内核的编译命令,第一节 Linux内核定制、裁剪和添加,2,第一节 Linux内核定制、裁剪
2、和添加 一、概述,1、操作系统结构 - 操作系统(Operating System,OS)是一组能够管理电脑软 硬件资源的程序,它能够管理内存、决定系统资源分配、控制输入输出设备以及管理网络文件等。 - 操作系统能够使计算机系统资源得到最大限度的利用。 - 利用运行在某台计算机(宿主机)上的编译器编译某个源程序,生成在另一台机器(目标机)上运行的目标代码的过程。,3,- 操作系统包括五个方面的管理功能:进程与处理机管理、存储管理、设备管理、文件管理与用户管理。操作系统具有四个共同特征:并发性(concurrence)、共享性(sharing)、虚拟性(virtual)和不确定性(asynchr
3、onism)。- 并发是指两个或者多个事件在同一时间间隔之内发生;- 共享指系统中的资源能够供多个用户(用户程序)共同使用;- 虚拟指通过某种技术把一个物理上的实体映射为若干个逻辑上的对应;- 不确定性指内存中的多个进程均按照各自独立的方式执行,其执行速度由于受到操作系统的自动控制,因此是无法预知的。,一个操作系统至少具有如下图所示的结构。引导系统就是在操作系统内核运行之前运行的一段小程序,其作用是初始化硬件设备、建立内存空间的映射图,并且为最终调用操作系统内核准备好正确的环境; 内核是一个操作系统的核心,负责管理系统的进程、存储、设备和文件等,它决定着系统的性能和稳定性; 根文件系统并不是一
4、个具体的文件类型,而是一个理论性的概念,它作为VFS(Virtual Filesystem Switcher)的根节点,可以帮助后者管理文件系统。VFS是内核中提供的一种软件机制,能够提供实际各个文件系统的挂载点。,4,第一节 Linux内核定制、裁剪和添加 一、概述,2、内核源码安装 将ARM Linux 系统内核源码安装到操作系统之中不仅可以方便学习内核的相应内容,而且具有帮助编译驱动程序等功能。完整的内核一般规模较大,可以从官方网站http:/www.kernel.org下载。下载的内核一般是tar.gz或者是.bz2压缩文件,使用时需要解压。在编译内核注意需要root权限。以下为内核源
5、码的安装步骤:1)将需要升级的内核拷贝到/usr/src/下: #cp linux-2.4.18.tar.gz /usr/src 2)解压下载的源程序文件,命令如下所示: #tar zxvf linux-2.4.18.tar.gz 3)文件将解压到/usr/src/linux目录中,建立链接: #ln s linux-2.4.18 linux,5,第一节 Linux内核定制、裁剪和添加 一、概述,第一节 Linux内核定制、裁剪和添加 一、概述,3、内核版本号说明 可以使用uname a命令或者cat /proc/version命令来查看系统的内核版本号,如下图所示。该系统内核版本号为2.4.
6、20-8。其中第一个数字为主版本号,第二个数字为次版本号,第三个数字为修订号。如果次版本号为偶数,则表明是该版本是稳定发行版本;如果次版本号是奇数,则说明该系统内核仍在开发中。,6,现代的操作系统一般由进程管理、内存管理、文件系统、驱动程序和网络等几个功能模块组成 。Linux内核源码的各个目录大致与此相对应,如下图所示。,第一节 Linux内核定制、裁剪和添加 二、内核目录介绍,7,内核源码目录说明,8,第一节 Linux内核定制、裁剪和添加 二、内核目录介绍,1配置文件 给用户提供配置选择的功能,主要包括如下配置文件,9,第一节 Linux内核定制、裁剪和添加 三、配置文件和配置工具,2配
7、置工具 用来进行相关配置的工具,包括配置命令解释器,其中配置用户界面如下: (1)基于字符的界面 使用命令: Make config 该方法简单且不需要调用Xwindows,不过操作麻烦,用户界面不友好。,10,第一节 Linux内核定制、裁剪和添加 三、配置文件和配置工具,(2)基于Ncurses的文本模式图形用户界面 使用命令: make menuconfig 该方法简单且不需要调用Xwindows,而且操作简单,用户界面友好后面的实验就使用该方法进行内核的相关配置。,11,第一节 Linux内核定制、裁剪和添加 三、配置文件和配置工具,(3)基于Xwindows图形界面的用户配置界面 使
8、用命令: Make xconfig,12,第一节 Linux内核定制、裁剪和添加 三、配置文件和配置工具,1在该级目录下的Config.in中添加对该模块的编译条件,该变量可以设置为三种状态 Y -将该功能模块编译进内核 N -不将该功能模块编译进内核 M -将该功能编译成模块方式,可以在需要时动态插入到内核中的模块,13,第一节 Linux内核定制、裁剪和添加 四、内核的编译命令,2内核的编译操作 下面给出了用于内核编译的主要命令:# make menuconfig -配置编译选项 # make dep -提供变量依赖关系信息. # make clean -删除生成的模块和目标文件. # m
9、ake zImage -编译内核生成压缩的映象. # make modules -编译模块. # make modules_install -安装编译完成的模块.编译完成之后最终生成的压缩内核映象的路径为arch/arm/boot/zImage,之后拷贝新内核文件zImage到启动目录,并改为合适的名字,即可启动新完成的内核镜像。,14,第一节 Linux内核定制、裁剪和添加 四、内核的编译命令,内容:一、引导系统概述 简单介绍引导系统的概念和模式二、Linux的Bootloader vivi与uboot vivi和uboot作为ARM平台常用的引导程序,具有结构简单但是功能强大的特点,第二节
10、 嵌入式引导系统(BootLoader)技术,15,1引导系统介绍引导程序(BootLoader),即系统加电后运行的第一段软件代码。一般来说嵌入式系统的Bootloader负责加载整个启动任务。整个过程包括初始化硬件设备、建立内存空间的映射图、配置合适的软硬件环境以便能够调用操作系统的内核。,第二节 嵌入式引导系统(BootLoader)技术 一、引导系统概述,16,2引导系统的操作模式 大多数引导系统都包含两种不同的操作模式:启动加载模式下载模式1)启动加载模式启动加载模式也称为“自主”(autonomous)模式。引导系统从目标机上的某个固态存储设备中将操作系统加载到 RAM 中运行。这
11、种模式是引导系统的正常工作模式。2)下载模式在下载模式下,目标机上的引导系统将通过串口连接或网络连接等通信手段从主机下载文件。从主机下载的文件通常首先被引导系统保存到目标机的RAM中,然后再被引导系统写到目标机上的FLASH类固态存储设备中。这种模式通常在第一次安装内核与根文件系统时使用;此外,以后的系统更新也会使用引导系统的这种工作模式。,第二节 嵌入式引导系统(BootLoader)技术 一、引导系统概述,17,3. 引导系统的主要任务与典型结构框架 大多数引导系统都分为 stage1 和 stage2 两大部分。依赖于处理器体系结构和板级初始化的代码通常都放在 stage1 中,用汇编实
12、现;而 stage2 则通常用C语言来实现,这样可以实现更复杂的功能,同时代码具有更好的可读性和可移植性。,第二节 嵌入式引导系统(BootLoader)技术 一、引导系统概述,18,引导系统的 stage1:1)硬件设备初始化。 2)为加载引导系统的 stage2 准备 RAM 空间。 3)拷贝引导系统的 stage2 到RAM空间中。 4)设置好堆栈。 5)跳转到 stage2 的 C 入口点,引导系统的 stage2 :1)初始化本阶段要用到的硬件设备。 2)检测系统内存映射(memory map)。 3)将内核映像和根文件系统映像从flash上读到 RAM 空间中。 4)为内核设置启动
13、参数。 5)调用内核。,1vivi的常用命令 - 帮助命令vivi help- 显示启动参数vivi param show- 启动参数帮助vivi param help- 设置参数vivi param set boot_delay 10000000Change boot_delay value. 0x00989680(10000000) to 0x00989680(10000000)vivi param save,第二节 嵌入式引导系统(BootLoader)技术 二、 Linux的Bootloader vivi与uboot,19,1vivi的常用命令 - 显示分区帮助vivi part he
14、lp- 显示分区vivi part show- 存储器分区vivi bon help- 引导帮助vivi boot help- 启动操作系统vivi boot,第二节 嵌入式引导系统(BootLoader)技术 二、 Linux的Bootloader vivi与uboot,20,2Uboot 的常用命令1)protect:protect命令用于对Flash进行写保护,可以使能和解除写保护。 2)erase:erase命令可以擦除Flash。 3)setenv:setenv命令可以设置环境变量。 4)printenv:printenv命令可以打印全部环境变量,也可以只打印参数中列出的环境变量。
15、5)tftpboot:tftpboot命令能够使用TFTP协议通过网络下载二进制格式的文档。另外,使用这个命令,必须配置好相关的环境变量。例如serverip和ipaddr。其命令格式为:tftpboot loadAddress bootfilename 6)bootm: bootm命令可以引导启动存储在内存中的程序映像。这些内存包括RAM和可以永久保存的Flash。其命令格式为:bootm addr arg .,第二节 嵌入式引导系统(BootLoader)技术 二、 Linux的Bootloader vivi与uboot,21,2Uboot 的常用命令7)go:go命令能够执行应用程序。其
16、命令格式为:go addr arg . 8)loadb:loadb命令能够通过串口线下载二进制格式的文档。其命令格式为:loadb off baud 9)loads:loads命令可以通过串口线下载S-Record格式的文件。 10)flinfo:flinfo命令打印全部Flash组的信息,也可以只打印其中某个组的信息。一般嵌入式系统的Flash只有一个组。 11)cp:cp命令可以在内存中复制数据块,包括对Flash的读写操作。,第二节 嵌入式引导系统(BootLoader)技术 二、 Linux的Bootloader vivi与uboot,22,2Uboot 的常用命令12)cmp:cmp
17、命令可以比较两块内存中的内容。.b表示以字节为单位;.w表示以字为单位;.l表示以长字为单位。 13)mw:mw命令可以按照字节、字、长字写内存,.b ,w,l的用法与cp命令相同。 14)nfs:nfs命令可以使用NFS网络协议通过网络启动映像。 15)nm:nm命令用于修改内存,可以按照字节、字、长字操作。 16)run:run命令可以执行环境变量中的命令,后面参数可以是几个环境变量名。 17)sleep:sleep命令可以延迟N秒钟执行,N为十进制数。,第二节 嵌入式引导系统(BootLoader)技术 二、 Linux的Bootloader vivi与uboot,23,内容:一、文件系
18、统概述包括根文件系统的概述以及根文件系统的目录结构二、BusyBoxBusyBox的介绍以及相关命令,第三节 文件系统的构建,24,1根文件系统描述- Linux引导启动时,默认使用的文件系统是根文件系统。装载根文件系统也是引导系统启动过程的最后一个步骤。- 文件系统包含两大类:根文件系统和附加文件系统。- 根文件系统是操作系统至少应该引导的一个文件系统,它包含了构建整个操作系统的基本程序和相关目录- 附加文件系统则是除了根文件系统之外的所有文件系统,本身无法直接使用,需要挂载到根文件系统的某个目录下方可使用。,第三节 文件系统的构建 一、文件系统概述,25,第三节 文件系统的构建 一、文件系
19、统概述,26,2根文件系统目录结构根文件系统呈倒挂树状层次结构,一般包括如下几个目录:/etc、 /dev、/usr、/bin、 /var等。 如下图所示:,第三节 文件系统的构建 一、文件系统概述,27,各目录功能如下:,1BusyBox介绍BusyBox combines tiny versions of many common UNIX utilities into a single small executable. It provides replacements for most of the utilities you usually find in GNU fileutils,
20、 shellutils, etc. The utilities in BusyBox generally have fewer options than their full-featured GNU cousins; however, the options that are included provide the expected functionality and behave very much like their GNU counterparts. BusyBox provides a fairly complete environment for any small or em
21、bedded system.事实上,BusyBox提供了相当多的工具。从最简单的显示工具到最强大的搜索工具,BusyBox把这些工具存放在/bin和/sbin目录之下,并且建立一个能够使用这些工具的链接。,第三节 文件系统的构建 二、BusyBox,28,2. BusyBox的相关命令BusyBox的相关配置和编译内核类似,需要首先使用make menuconfig命令进行手工配置。敲下make menuconfig命令之后,进入如下界面:,第三节 文件系统的构建 二、BusyBox,29,2. BusyBox的相关命令BusyBox其他命令包括: help 显示 make 选项的完整列表 d
22、efconfig 启用默认的(通用)配置 allnoconfig 禁用所有的应用程序(空配置) allyesconfig 启用所有的应用程序(完整配置) allbareconfig 启用所有的应用程序,但是不包括子特性 config 基于文本的配置工具 menuconfig N-curses(基于菜单的)配置工具 all 编译 BusyBox 二进制文件和文档(./docs) busybox 编译 BusyBox 二进制文件 clean 清除源代码树 distclean 彻底清除源代码树 sizes 显示所启用的应用程序的文本/数据大小,第三节 文件系统的构建 二、BusyBox,30,本章主
23、要介绍了三个部分,分别是嵌入式linux内核、引导系统介绍和文件系统等相关内容。在内核部分详细介绍了Linux操作系统内核定制、裁剪和添加;引导部分则介绍了嵌入式BootLoader技术;最后的文件系统部分详细介绍了文件系统的构建。章节的最后部分将构建Floppylinux作为一个综合应用实验,试图让读者更加深入理解上述3块内容。,小结,31,1. 请简述操作系统的结构。 2. 请简述操作系统的特点并举例说明。 3. 请列举出Linux内核源码的所有文件夹,并且说明每个文件夹的意义。 4. 请列举出Linux有关内核镜像的三种编译方法,并陈述每个方法的特点。 5. 请简述Linux引导系统过的
24、两种操作模式并分别说明。 6. 请列举出根文件系统的所有目录,并且分别说明每个文件夹的含义。 7. 请阐述Linux内核编译的选项和BusyBox编译选项之间的区别。 8. 请完成本章的综合实验FloppyLinux。 9. 请尝试完成基于U盘的Linux系统。,习题,32,Linux内核启动简析(汇编部分),第一段代码位于arch/arm/boot/compressed/start.S:start:1: mov r7, r1 保存machine idmov r8, r2 保存参数地址mrs r2, cpsr 确定不是在USER模式下tst r2, #3bne not_angel not_an
25、gel:mrs r2, cpsr 强制转换到SVC模式orr r2, r2, #0xc0msr cpsr_c, r2,Linux内核启动简析(汇编部分),Bss段清零:not_relocated: mov r0, #01: str r0, r2, #4 R2,BSS开始str r0, r2, #4str r0, r2, #4str r0, r2, #4cmp r2, r3 R3,BSS结束blo 1b,Linux内核启动简析(汇编部分),跳转到C语言实现的解压内核代码:. .mov r5, r2 246mov r0, r5mov r3, r7bl decompress_kernel 实现代码在
26、arch/arm/boot/compressed/misc.c中,解压代码: ulg decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, int arch_id) output_data = (uch *)output_start; free_mem_ptr = free_mem_ptr_p; free_mem_ptr_end = free_mem_ptr_end_p; _machine_arch_type = arch_id; arch_decomp_setup(); makecrc(
27、); putstr(“Uncompressing Linux.“); gunzip(); putstr(“ done, booting the kernel.n“); return output_ptr; ,Linux内核启动简析(汇编部分),call_kernel: bl cache_clean_flush 清除cache bl cache_off 关闭cache mov r0, #0 mov r1, r7 machine ID mov r2, r8 参数地址 mov pc, r4 跳转到arch/arm/kernel/head.S中,Linux内核启动简析(汇编部分),arch/arm/k
28、ernel/head.S 跳转到此处时处理器的状态:MMU关闭D-cache关闭I-cache是否关闭不重要R0中是0R1中是machine IDR2中是启动参数地址,Linux内核启动简析(汇编部分),ENTRY(stext) msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE mrc p15, 0, r9, c0, c0 bl _lookup_processor_type movs r10, r5 beq _error_p bl _lookup_machine_type movs r8, r5 beq _error_a bl _vet_atags b
29、l _create_page_tables,Linux内核启动简析(汇编部分),lookup_processor_type 作用是从硬件中读出CPU的ID,与编译内核时 选择的CPU的ID进行比较。如果不一样,则不 能成功启动。 比如,如果在arm920t的CPU上运行为其他CPU 编译的内核,这里就通不过。,Linux内核启动简析(汇编部分),lookup_machine_type 将R1的内容(machine ID)与编译内核时选择的machine ID比较,如果不同,则内核不能成功启动。 vet_atags检查tag(内核的启动参数)的合法性,Linux内核启动简析(汇编部分),crea
30、te_page_tables 首先将内核启动地址前0x4000(共16KB)的内存空间清零,以便作为内核页表使用。 然后,清除I-cache、D-cache,使能MMU,为跳转到C语言实现部分做准备,Linux内核启动简析(汇编部分),Linux内核启动简析(c语言部分),C语言入口在init/main.c中: asmlinkage void _init start_kernel(void) early_boot_irqs_off(); page_address_init(); printk(KERN_NOTICE); printk(linux_banner); setup_command_l
31、ine(command_line); printk(KERN_NOTICE “Kernel command line: %sn“, boot_command_line); init_IRQ(); mem_init(); rest_init(); ,Linux内核的配置(1/6),1、.config文件 这是linux编译时所依赖的文件。我们在配置内核时所做的任何修改,最终都会在这个文件中体现出来。它是Makefile对内核进行处理的重要依据。 一般来说,内核提供了芯片公司demo板的.config文件,我们一般找一个近似的进行修改。如S3C2410平台上可以选择s3c2410_deconfig
32、这个文件。,Linux内核的配置(2/6),三种配置方式 make config 基于文本对话的配置方式,比较细致,但是浪费时 间。对专业的内核开发人员比较合适。 make xconfig 基于图形界面的配置方式。非常直观,但是需要特殊 的软件支持,一般不推荐。 make menuconfig 推荐的内核配置方式,采用目录的方式,直观,容易 使用。,Linux内核的配置(3/6),关于Kconfig 在进行make menuconfig时,目录的生成依赖于Kconfig 文件。一般来说,每个源代码目录下都有一个Kconfig 文件。 config DM9000 tristate “DM9000
33、 support“ depends on ARM | BLACKFIN | MIPS select CRC32 select MII -help- Support for DM9000 chipset. To compile this driver as a module, choose M here. The module will be called dm9000.,Linux内核的配置(4/6),Kconfig对.config文件的影响: CONFIG_DM9000=y make menuconfig对内核配置所做的修改最终反应 在.config文件中。如上所示,在.config文件中
34、CONFIG_DM9000=y被定义为y。,Linux内核的配置(5/6),Kconfig对Makefile的影响: obj-$(CONFIG_DM9000) += dm9000.o CONFIG_DM9000是tristate类型,有三个可能取值: y:编译进内核 m:编译成模块 n:不进行编译 若是bool类型,则只有两种可能,y或者n。,Linux内核的配置(6/6),关于Makefile Linux内核源码的每个目录下都有一个Makefile,由该 Makefile对源代码的编译、链接等操作进行控制。 编译完成后,每个源代码目录下都会生成一个名叫 built-in.o的文件。这个文件由
35、源代码目录下的所以 源文件编译后的目标文件链接而成;而不同的builtin. o又被上层目录中的Makefile链接成更大的builtin. o,直到最后链接成为一个内核vmlinux.o。,Linux内核移植交叉编译,关于交叉编译 由于我们的目标平台是ARM,而在x86平台上进行开发,故必须进行交叉编译。 修改内核的顶层Makefile: ARCH ?= arm CROSS_COMPILE ?= arm-linux- 表示我们的目标平台是ARM构架的,而使用的交叉编译 器的前缀是arm-linux,Linux内核移植.config,获得.config文件 前面提到,.config是内核编译时
36、所依赖的重要文件,与具体的硬件构架和开发板类型相关。我们选择内核提供的s3c2410_defconfig进行修改。 cp arch/arm/configs/s3c2410_defconfig .config,Linux内核移植demo板选择,选择相近的demo板 三星公司针对s3c2410芯片推出了smdk2410 demo板,Linux内核对该开发板的支持非常完善。为了移植方便,并最大可能地实现代码重用,我们选择该开发板作为原始目标板,在它的基础上进行必要的修改。在include/asm-arm/mach-types.h中#defineMACH_TYPE_SMDK2410 193与Bootl
37、oader中使用的machine ID是一致的。,Linux内核移植NAND,经典2410的NAND Flash 经典2410平台上配置一片K9F2808U NAND Flash,容量 大小为64M。为了使内核能正常使用NAND Flash,需要 在内核中正确地配置NAND Flash驱动支持。,添加NAND Flash支持在arch/arm/plat-s3c24xx/common-smdk.c中: static struct mtd_partition smdk_default_nand_part = 0 = .name = “Bootloader“, .size = 0x80000, /
38、512KB .offset = 0, ,1 = .name = “Linux Kernel“, .offset = 0x80000, .size = 0x200000, / 2MB ,2 = .name = “Root File System“, .offset = 0x280000, .size = 0x400000, / 4MB ,3 = .name = “User Space“, .offset = 0x680000, .size = 0x3980000, / 57.5MB ,Linux内核移植NAND,将NAND驱动加入初始化列表 struct platform_device s3c_
39、device_nand = .name = “s3c2410-nand“, .id = -1, .num_resources = ARRAY_SIZE(s3c_nand_resource), .resource = s3c_nand_resource, ; static struct platform_device _initdata *smdk_devs = ,Linux内核移植NAND,Linux内核移植LCD,添加LCD支持 经典2410平台上配置了一个640*480的lcd,需要在 内核中对LCD进行正确的配置,才能使用LCD。 配置LCD需要涉及到2410的lcd控制器、IO引脚功能
40、 配置,根据LCD的具体参数对lcd控制器进行配置。,填充display结构体: static struct s3c2410fb_display up2410_fb _initdata = .lcdcon5 = (112)|(111)|(19)|(18)|(10), .type = (35), / TFT .width = 640, / width .height = 480, / heigth .pixclock = 39721, .xres = 640, .yres = 480, .bpp = 16, .left_margin = 40, .right_margin = 32, .hsyn
41、c_len = 32, .vsync_len = 2, .upper_margin = 35, .lower_margin = 5, , ;,Linux内核移植LCD,指定初始化lcd设备: static struct platform_device *smdk2410_devices _initdata = ,Linux内核移植LCD,Linux内核移植网卡,添加网卡支持 经典2410平台上配置了DM9000A网卡,地址范围是 0x100000000x10000200,中断使用EINT2。Linux 内核中实现了网卡的驱动程序,但是需要我们进行一些必要的配置。,定义端口地址和中断号: sta
42、tic struct resource dm9000_res = 0 = .start = 0x10000000, .end = 0x10000200, .flags = IORESOURCE_MEM, , 1 = .start = IRQ_EINT2, .end = IRQ_EINT2, .flags = IORESOURCE_IRQ, ;,Linux内核移植网卡,添加设备信息: struct platform_device dm9000_dev = .name = “dm9000“, .id = -1, .num_resources = ARRAY_SIZE(dm9000_res), .resource = dm9000_res, ; 加入初始化队列: static struct platform_device *smdk2410_devices _initdata = ,Linux内核移植网卡,S3c2410芯片的配置: static void uptech_dm9000_init(void) u32 bwscon; bwscon = _raw_readl(S3C2410_BWSCON); bwscon ,Linux内核移植网卡,