构建stm32f407-uClinux的initramfs根文件系统

       上文讲到内核运行到free init memory:8k这个地方就卡住,运行不下去了,在查阅了相关资料后,推测是缺少根文件系统所导致的,原来的内核源代码是搭配有根文件系统的bin文件,是romfs但没有源码,前面讲过我现在项目使用的是stm32f407,内部flash容量和外部SRAM都不足以拷入这个原配的romfs挂起为根文件系统来使用。

       接下来就是寻找一种经济适用的文件系统来作为内核的根文件系统,从网上查阅相关资料可以知道,YAFFS2支持的是nandflash,jffs支持nor flash,这些看来对于我手上的stm32f407来说是不适用的,于是我仔细研究了stm32f103的源代码,发现它是有两种启动的方式,一种采用的是用iniramfs作为根文件系统,xip启动,在stm32f103内部flash只有512k的情况居然跑起了Uclinux,另一种是jfss2挂在外部nor flash上,显然我这种情况目前只有参考第一种方式来,采用initramfs作为根文件系统。于是开始构建initramfs相关文件。 仔细研究stm32f103 XIP启动方式的内核配置make menuconfig中, CONFIG_INITRAMFS_SOURCE=”initramfs-filelist” 而initramfs-filelist位于Uclinux/linux-2.6.x下,打开一看是这样的:


这里写图片描述

       一开始我看不懂这里面的shell什么意思,好吧,不懂就继续找度娘,找到在一篇文章当中写得很清楚了,下面我把它copy过来,转载一下:


把initramfs编译到内核里面去

       使用initramfs最简单的方式,莫过于用已经做好的cpio.gz把kernel里面那个空的给换掉。这是2.6 kernel天生支持的,所以,你不用做什么特殊的设置。

       kernel的config option里面有一项CONFIG_INITRAMFS_SOURCE(I.E. General setup—>Initramfs source file(s) in menuconfig)。这个选项指向放着内核打包initramfs需要的所有文件。默认情况下,这个选项是留空的,所以内核编译出来之后initramfs也就是空的,也就是前面提到的rootfs什么都不做的情形。

C       ONFIG_INITRAMFS_SOURCE 可以是一个绝对路径,也可以是一个从kernel’s top build dir(你敲入build或者是make的地方)开始的相对路径。而指向的目标可以有以下三种:一个已经做好的cpio.gz,或者一个已经为制作cpio.gz准备好所有内容的文件夹,或者是一个text的配置文件。第三种方式是最灵活的,我们先依次来介绍这三种方法。

1)使用一个已经做好的cpio.gz档案

       If you already have your own initramfs_data.cpio.gz file (because you created it yourself, or saved the cpio.gz file produced by a previous kernel build), you can point CONFIG_INITRAMFS_SOURCE at it and the kernel build will autodetect the file type and link it into the resulting kernel image.

       You can also leave CONFIG_INITRAMFS_SOURCE empty, and instead copy your cpio.gz file to usr/initramfs_data.cpio.gz in your kernel’s build directory. The kernel’s makefile won’t generate a new archive if it doesn’t need to.

       Either way, if you build a kernel like this you can boot it without supplying an external initrd image, and it’ll still finish its boot by running your init program out of rootfs. This is packaging method #2, if you’d like to try it now.

2)指定给内核一个文件或者文件夹

       If CONFIG_INITRAMFS_SOURCE points to a directory, the kernel will archive it up for you. This is a very easy way to create an initramfs archive, and is method #3.

       Interestingly, the kernel build doesn’t use the standard cpio command to create initramfs archives. You don’t even need to have any cpio tools installed on your build system. Instead the kernel build (in usr/Makefile) generates a text file describing the directory with the script “gen_initramfs_list.sh”, and then feeds that descript to a program called “gen_init_cpio” (built from C source in the kernel’s usr directory), which create the cpio archive. This looks something like the following:

scripts/gen_initramfs_list.sh $CONFIG_INITRAMFS_SOURCE > usr/initramfs_list
usr/gen_init_cpio usr/initramfs_list > usr/initramfs_data.cpio
gzip usr/initramfs_data.cpio
To package up our hello world program, you could simply copy it into its own directory, name it “init”, point CONFIG_INITRAMFS_SOURCE at that directory, and rebuild the kernel. The resulting kernel should end its boot by printing “hello world”. And if you need to tweak the contents of that directory, rebuilding the kernel will re-package the contents of that directory if anything has changed.

       The downside of this method is that it if your initramfs has device nodes, or cares about file ownership and permissions, you need to be able to create those things in a directory for it to copy. This is hard to do if you haven’t got root access, or are using a cross-compile environment like cygwin. That’s where the fourth and final method comes in.

3)使用configuration文件initramfs_list来告诉内核initramfs在哪里

       This is the most flexible method. The kernel’s gen_initramfs_list.sh script creates a text description file listing the contents of initramfs, and gen_init_cpio uses this file to produce an archive. This file is a standard text file, easily editable, containing one line per file. Each line starts with a keyword indicating what type of entry it describes.

The config file to create our “hello world” initramfs only needs a single line:

       file /init usr/hello 500 0 0
       This takes the file “hello” and packages it so it shows up as /init in rootfs, with permissions 500, with uid and gid 0. It expects to find the source file “hello” in a “usr” subdirectory under the kernel’s build directory. (If you’re building the kernel in a different directory than the source directory, this path would be relative to the build directory, not the source directory.)

       To try it yourself, copy “hello” into usr in the kernel’s build directory, copy the above configuration line to its own file, use “make menuconfig” to point CONFIG_INITRAMFS_SOURCE to that file, run the kernel build, and test boot the new kernel. Alternately, you can put the “hello” file in its own directory and use “scripts/gen_initramfs_list.sh dirname” to create a configuration file (where dirname is the path to your directory, from the kernel’s build directory). For large projects, you may want to generate a starting configuration with the script, and then customize it with any text editor.

       This configuration file can also specify device nodes (with the “nod” keyword), directories (“dir”), symbolic links (“slink”), named FIFO pipes (“pipe”), and unix domain sockets (“sock”). Full documentation on this file’s format is available by running “usr/gen_init_cpio” (with no arguments) after a kernel build.

A more complicated example containing device nodes and symlinks could look like this:

dir /dev 755 0 0
nod /dev/console 644 0 0 c 5 1
nod /dev/loop0 644 0 0 b 7 0
dir /bin 755 1000 1000
slink /bin/sh busybox 777 0 0
file /bin/busybox initramfs/busybox 755 0 0
dir /proc 755 0 0
dir /sys 755 0 0
dir /mnt 755 0 0
file /init initramfs/init.sh 755 0 0
       One significant advantage of the configuration file method is that any regular user can create one, specifying ownership and permissions and the creation of device nodes in initramfs, without any special permissions on the build system. Creating a cpio archive using the cpio command line tool, or pointing the kernel build at a directory, requires a directory that contains everything initramfs will contain. The configuration file method merely requires a few source files to get data from, and a description file.

       This also comes in handy cross-compiling from other environments such as cygwin, where the local filesystem may not even be capable of reproducing everything initramfs should have in it.

总结一下

       这四种给rootfs提供内容的方式都有一个共同点:在kernel启动时,一系列的文件被解压到rootfs,如果kernel能在其中找到可执行的文件“/init”,kernel就会运行它;这意味着,kernel不会再去理会“root=”是指向哪里的。

       此外,一旦initramfs里面的init 进程运行起来,kernel就会认为启动已经完成。接下来,init将掌控整个宇宙!它拥有霹雳无敌的专门为它预留的Process ID #1,整个系统接下来的所有都将由它来创造!还有,它的地位将是不可剥夺的,嗯哼,PID 1 退出的话,系统会panic的。

接下来我会介绍其他一些,在rootfs中,init程序可以做的事。

Footnote 1: The kernel doesn’t allow rootfs to be unmounted for the same reason the same reason it won’t let the first process (PID 1, generally running init) be killed. The fact the lists of mounts and processes are never empty simplifies the kernel’s implementation.

Footnote 2: The cpio format is another way of combining files together, like tar and zip. It’s an older and simpler storage format that dates back to the original unix, and it’s the storage format used inside RPM packages. It’s not as widely used as tar or zip because the command line syntax of the cpio command is unnecessarily complicated (type “man 1 cpio” at a Linux or Cygwin command line if you have a strong stomach). Luckily, we don’t need to use this command.

Footnote 3: The kernel will always panic if PID 1 exits; this is unrelated to initramfs. All of the signals that might kill init are blocked, even “kill -9” which will reliably kill any other process. But init can still call the exit() syscall itself, and the kernel panics if this happens in PID 1. Avoiding it here is mostly a cosmetic issue: we don’t want the panic scrolling our “Hello World!” message off the top of the screen.

Footnote 4: Statically linking programs against glibc produces enormous, bloated binaries. Yes, this is expected to be over 400k for a hello world proram. You can try using the “strip” command on the resulting binary, but it won’t help much. This sort of bloat is why uClibc exists.

Footnote 5: Older 2.6 kernels had a bug where they would append to duplicate files rather than overwriting. Test your kernel version before depending on this behavior.

Footnote 6:User Mode Linux or QEMU can be very helpful testing out initramfs, but are beyond the scope of this article.

Footnote 7: Well, sort of. The default one is probably meant to be empty, but due to a small bug (gen_initramfs_list.sh spits out an example file when run with no arguments) the version in the 2.6.16 kernel actually contains a “/dev/console” node and a “/root” directory, which aren’t used for anything. It gzips down to about 135 bytes, and might as well actually be empty. On Intel you can run “readelf -S vmlinux” and look for section “.init.ramfs” to see the cpio.gz archive linked into a 2.6 kernel. Elf section names might vary a bit on other platforms.

        显然stm32f103使用的是第三种方法,里面那些指令无非是设置文件权限、设置软连接等等操作,期间还学了一点bash shell,又有点收获,明白了道理之后就好办了,直接照猫画虎,我采用的是第二种方法:

1、先创建rootfs这个文件夹,再在这个文件夹下面分别创建bin、dev、etc、proc、sys等目录

2、编译busybox,把生成的bin文件复制到rootfs/bin下

3、新建linuxrc文件,设置权限chmod 777,然后在u-boot传给内核参数中一定要加上init=/linuxrc

4、在dev目录下,加设备节点,不然会没有输出信息哦!

mknod -m 666 console c 5 1
   mknod -m 666 null c 1 3

5、在内核make menuconfig上CONFIG_INITRAMFS_SOURCE=“你刚刚构建的文件夹的绝对路径”

       编译内核,initramfs直接和内核编译在一起,不用另外分出一个bin文件拷,这比较方便,启动,在串口调试助手中可看到相关显示信息:


这里写图片描述

       最后说一下自己的想法,用initramfs根文件系统虽然方便实用,但是有弊端就是它只读不可写,这对开发很不利,领导说会加个spi flash再在里面挂载个根文件系统(spi flash能挂jfss2吗?),那是以后的事了以后再说,目前这种情况以我的技术水平只能做到这个份上了,加了根文件之后,stm32内部flash还有200多k的存储空间,应该可以添加些驱动和应用程序,那下面我的任务是编写简单的驱动与应用程序,好吧,又得继续学习,努力工作了。。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值