原链接地址:
https://github.com/ir193/tiny_linux/blob/master/NOTE.md
制作小系统的思路。
正文开始
=================================================================================
This is my note of doing the project for advanced operating systems. I'll try to log tools needed, the configure I used and the pitfalls during the this project.
这是我做小系统的笔记。我尽努力记下过程中所使用的工具,配置和遇到的坑。
We’ll be building:
1. A tiny custom [Linux kernel][1]. And try to make its size as small as possible by disable some kernel feature/function, and also by patch the kernel source code.
2. A ramdisk served as main filesystem, with some configure to setup network working.
我们的目标:
1. 一个基于linux的小系统。尽量的去掉内核的多余特性和功能,及源码补丁。
2. ramdisk作为文件系统, 带网络功能。
The host and target will both be x86.
宿主机和目标机都是x86系统。
Some useful tutorial:
* http://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html
* http://www.linuxfromscratch.org/
Some useful example:
* http://distro.ibiblio.org/tinycorelinux/
一些有用的教程:
* http://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html
* http://www.linuxfromscratch.org/
有用的例子:
* http://distro.ibiblio.org/tinycorelinux/
#Preparation#
#准备工作#
Setup neccessary toolchains and libraries, at least:
安装必须的工具链和库, 至少包括:
* gcc (for building linux kernel and busybox)
* curl (for download)
* ncurses (for linux menuconfig)
Now, let's get started
现在开始
First, setup a working directory and some environment variable for convenience
首先,创建工作目录和配置环境变量
mkdir $HOME/tiny_linux
TOP=$HOME/tiny_linux
cd $TOP
Download source code of [linux kernel][1]:
下载linux内核源码和busybox源码
curl https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.0.4.tar.xz | tar xJf -
Downlaod source code of [busybox][2]
curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf -
#Build Linux Kernel#
#编译内核#
Now build a linux kernel with default config. Before configure&make, create a directory for obj files to keep kernel source clean and some variables for convenience
使用默认config编译linux 内核。 开始之前先创建obj文件夹存放编译后文件,以及添加一些环境变量。
cd $TOP
mkdir obj
mkdir obj/linux_defconfig
LINUX_SRC=$TOP/linux-4.0.4
cd $LINUX_SRC
make O=../obj/linux_defconfig i386_defconfig
Now the config has been write into $TOP/obj/linux_defconfig. Go into it and compile
生成的config文件放在$TOP/obj/linux_defconfig。开始编译
cd $TOP/obj/linux_defconfig
make
If no error message reported, you should see
如果没有错误的话,编好的内核文件在下面目录可以找到
> Kernel: arch/x86/boot/bzImage is ready (#1)
Test you bright new kernel with qemu:
使用qemu测试新内核:
qemu-system-i386 -kernel $TOP/obj/linux_defconfig/arch/x86/boot/bzImage
You should see linux running and finally a kernel panic. To see full log:
linux 启动运行 最后发生 kernel panic, 完整log 使用下面命令:
qemu-system-i386 -kernel $TOP/obj/linux_defconfig/arch/x86/boot/bzImage -append "console=ttyS0" -nographic
Note that when use `-nographic`, you can quit by hit `Ctrl-C` then `a`, then type `quit`
使用`-nographic`时,退出可以按 `Ctrl-C`, 然后`a`, 然后输入`quit`
The error log should be:
错误log如下:
> [ 3.711331] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
> [ 3.730405] Please append a correct "root=" boot option; here are the available partitions:
That means our kernel works fine, but it can't find root device. Next we create the root device, a ramdisk.
这个错误是正常的,说明内核已经运行,但是没有找到 root 设备。下面我们创建一个ramdisk 设备。
Before that, just copy the kernel image into obj directory.
内核最后一步,创建一个变量,方便后面调用。
cp $TOP/obj/linux_defconfig/arch/x86/boot/bzImage $TOP/obj
KERNEL=$TOP/obj/bzImage
#Build Root Filesystem#
#创建根文件系统#
Now we focus on the userland level, we will use [Busybox][2]. 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, shellutils, etc.
根文件系统需要用到busybox。busybox 集成了常用的文件操作和shell 命令,所有命令指向同一个可执行程序,体积小,适合小系统使用。
First we build busybox:
首先创建环境变量,生成配置文件
cd $TOP
mkdir obj/busybox
cd $TOP/busybox-1.23.2
make O=../obj/busybox/ defconfig
IMPORTANT, config busybox to static linked
【重要点】, 选择将busybox编译成静态链接
make O=../obj/busybox/ menuconfig
choose:
选择:
Busybox Setting:
Build Option
Build Busybox as a static binary
Ok, just build it (in obj directory, to keep source code clean)
进到obj目录,开始编译
cd $TOP/obj/busybox
make
make install
Note that here we use a make install, but this will NOT install busybox into your HOST system. Relax.
注意:执行make install 并不是将busybox安装到你的宿主机,所以放轻松。
You can simplely run the busybox to test if it works properly.
执行命令测试编译的busybox:
./busybox ls
Now create another directory to hold our filesystem hierarchy, and copy busybox into it.
现在创建一个目录用于保存filesystem,
a. 拷贝busybox。
cd $TOP/
mkdir ramdisk
cd ramdisk
cp -av $TOP/obj/busybox/_install/* .
Then create a simple init script for debug.
b. 建一个init文件,测试用
Recall what we learn on class, [init][3] process is the first userspace process. It takes care of services, runlevels and so on. All processes will fork from init. In real linux distribution, some typical init process are: systemd, Upstart, SysV
init 是用户空间的第一个进程。负责启动服务和运行等级等,其他所有的进程都由init启动。
在真实的linux发行版,典型的init进程包括:systemd, Upstart, SysV
echo -e '#!/bin/sh \n /bin/sh' > init
chmod +x init
To ensure kernel can execute script, we need linux kernel compiled with
linux内核运行脚本,需要修改编译选项:
Kernel support for scripts starting with #!
But when finish debug, we will use symbolic link busybox as init, then this option can be turned off.
但是稍后,我们将使用busybox软链接作为init,所以可以不选。
check again the symbolic link is correct. Then we can pack the filesystem into a cpio file.
确保软链接正确, 然后打包文件系统成cpio文件。
cd $TOP/ramdisk
find . -print0 | cpio --null -ov --format=newc | gzip -9 > $TOP/obj/initramfs.cpio.gz
RAMDISK=$TOP/obj/initramfs.cpio.gz
RUN IT~:
运行下面命令:
qemu-system-i386 -kernel $KERNEL -initrd $RAMDISK
If success, a shell will be ready when finish booting.
如果成功, 启动后可以输入shell命令
If you saw:
> /bin/sh: can't access tty; job control turned off
Don't worry, that's normal because our init simply launch a shell without necessary setup. We work on it in next step.
不用担心,这是由于我们没有安装sh,接下来将解决。
#Userland: init and mount#
#用户模式: init和mount#
We step back and remove the debug script. And create a symbolic link with busybox to subtitude it:
创建一个busybox到init的软链接
cd $TOP/ramdisk
rm init
ln -s bin/busybox init
So after kernel booting into userland, busybox will be called as init. Then busybox check configurations and do its job.
这样当kernel切换到用户模式, busybox 将被调用。 busybox将检查配置并做相应操作。
Before we write init configurations, we create some directory:
创建一些文件夹:
cd $TOP/ramdisk
mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin},dev}
That's more like a real linux system.
这样更像真实的操作系统。
Then busybox configuration:
busybox的配置文件:
cd $TOP/ramdisk
cd etc
vim inittab
The content of inittab can be:
inittab的内容
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
And rcS:
rcS的内容:
mkdir init.d
cd init.d
vim rcS
rcS will called after system init, we mount filesystem and initialize network here
rcS 在系统启动后调用,可以用来挂载文件系统和初始化网络
#!/bin/sh
mount proc
mount -o remount,rw /
mount -a
clear
echo "Booting Tiny Linux"
Don't forget attribute:
添加可执行权限:
chmod +x rcS
See the `mount -a`, it will check /etc/fstab. We create it:
`mount -a` 用到 /etc/fstab, 建一个:
cd $TOP/ramdisk/etc
vim fstab
The content:
/etc/fstab 的内容:
# /etc/fstab
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devtmpfs /dev devtmpfs defaults 0 0
OK for now, that's finish, pack it and run:
OK ,阶段性完成,打包运行试试:
cd $TOP/ramdisk
find . -print0 | cpio --null -ov --format=newc | gzip -9 > $TOP/obj/initramfs.cpio.gz
qemu-system-i386 -kernel $KERNEL -initrd $RAMDISK
We should see:
看到下面打印,成功!
Booting Tiny Linux
Please press Enter to activate this console.
Press Enter and get a shell. Check /dev /proc and /sys
看看下面几个目录。
ls /dev
ls /proc
ls /sys
Result should not be empty
不是空文件夹。
Finally, check ethernet card driver working:
最后查看网卡工作状态:
ifconfig -a
We should see `eth0` if ethernet card driver success.
看看有没有`eth0`
#Network#
#网络#
Keep editing /etc/init.d/rcS, add
向/etc/init.d/rcS,添加下面命令
/sbin/ifconfig lo 127.0.0.1 up
/sbin/route add 127.0.0.1 lo &
ifconfig eth0 up
ip addr add 10.0.2.15/24 dev eth0
ip route add default via 10.0.2.2
That's all.
以上。
Check our /etc/init.d/rcS again, it should contains:
完整的/etc/init.d/rcS文件:
#!/bin/sh
mount proc
mount -o remount,rw /
mount -a
clear
echo "Booting Tiny Linux"
/sbin/ifconfig lo 127.0.0.1 up
/sbin/route add 127.0.0.1 lo &
ifconfig eth0 up
ip addr add 10.0.2.15/24 dev eth0
ip route add default via 10.0.2.2
You can test it in your tiny system:
输入下面命令测试网络:
wget http://[you HOST os ip]:port/file
#Reducing the kernel size#
#减少内核大小#
run
运行下面命令:
cd $TOP/linux-4.0.4
make O=../obj/linux_defconfig menuconfig
turn off unneccessary features! Especially devices drivers
去掉不需要的功能, 尤其是驱动部分
To be continued
下面网站,获取更多信息
see http://elinux.org/Work_on_Tiny_Linux_Kernel
#A very tiny version#
#超小版本#
start over from zero config
首先关掉所有功能
cd $TOP/linux-4.0.4
make O=../obj/linux_defconfig allnoconfig
This will select no to all config. Then we should turn necessary option on.
上面命令关掉所有配置,然后按需打开。
For now, at least following options:
但至少包含下面选项:
Support for basic start up and debug log:
基本的启动选项和调试log:
>
> General setup --->
> Initial RAM filesystem and RAM disk (initramfs/initrd) support
> Support initial ramdisks compressed using gzip
> Optimize for size
> Embedded system
> Configure standard kernel features (expert users) -->
> Enable support for printk
> Executable file formats / Emulations --->
> Kernel support for ELF binaries
> Kernel support for scripts starting with #!
Support Ethernet card:
网卡支持:
> Bus options (PCI etc.) --->
> PCI support
>
>
> Networking support -->
> Networking options -->
> TCP/IP networking
> INET: socket monitoring interface
> Device Drivers -->
> Network device -->
> Network core driver support
> Ethernet driver support -->
> Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support
Some option depends on other options in order to be visible. Press / to see dependcy.
选项之间存在依赖关系,输入 / 可以查看。
#FAQ#
#FAQ#
1. I can't use `make menuconfig`
`make menuconfig` 不可用
Maybe you need install ncurse
安装 ncurse 试试
2. How can I see full log?
qemu-system-i386 查看完整启动log,使用下面命令
qemu-system-i386 -kernel $TOP/obj/linux_defconfig/arch/x86/boot/bzImage -append "console=ttyS0" -nographic
or inside you GUEST OS
或者进入系统后使用下面命令
dmesg | less
3. When I run qemu `error reading initrd: No such file or directory`
找不到 initrd?
Maybe you continue your work in anther shell? Check environment variable $TOP $KERNEL $RAMDISK is correct
先看看环境变量是否正确, 终端输入的变量,只在当前终端有效; 或者你可以使用完整文件路径
4. VFS: Cannot open root device "(null)"
启动根文件系统失败
check -initrd parameter and kernel compiled with initramfs support.
检查 -initrd 参数 和 内核编译是否支持 initramfs。
5. Kernel panic at boot: not syncing. No init found.
check busybox must be *staticaly* compiled
busybox 必须静态编译。
6. Generate ramdisk is slow and very large
生成ramdisk 慢又大
Execute command right under ramdisk root.
在ramdisk root下执行命令。
7. ifconfig report /proc/net/dev: No such file or directory
ifconfig 报 /proc/net/dev: No such file or directory
/proc is not properly mount. check fstab and rcS.
/proc 没有挂载成功,检查fstab 和 rcS。 也许是 windows 和 linux 格式的问题。
8. I can't see eth0
没有eth0
check ethernet device driver support. By default, QEMU emulate a Intel E1000 card. Note <M> means loadable kernel module and need mannually load.
检查网卡驱动是否支持,QEMU会仿真一个Intel E1000网卡, 如果内核是按模块编译的需要用户手动挂载。
9. I can't ping
ping功能
It's normal. Because QEMU default ethernet driver doesn't support ICMP.
QEMU 网卡驱动不支持 ICMP ,没有ping 功能。
10. A lot of error message
很多错误消息
It's normal as long as network can work.
看看网络能不能正常工作。
11. I can't get DHCP working
DHCP 不可用
NEITHER CAN I!
我的也是
12. But I can get DHCP working?
你行
DO tell me!
教下
#Reference#
#参考#
https://www.kernel.org/
http://busybox.net/
http://en.wikipedia.org/wiki/Inithttp://elinux.org/Work_on_Tiny_Linux_Kernel
http://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html
http://distro.ibiblio.org/tinycorelinux/
[1]: https://www.kernel.org/
[2]: http://busybox.net/
[3]: http://en.wikipedia.org/wiki/Init
[4]: http://elinux.org/Work_on_Tiny_Linux_Kernel
[5]: http://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html
[6]: http://distro.ibiblio.org/tinycorelinux/