target硬件配置为:
host也是vmware虚拟机, 安装 debian 5.0 lenny. 把 target 硬盘连接在 host 上(scsi 0:3, linux 设备节点为 /dev/sdd)
host 上用户名为v4, 工作目录为 ~/toy
需要的一些软件包放在~/tarballs/
0: 目标
========
建立一个最小的linux系统
- bootloader 用 grub
- 安装 busybox
- 安装 uclibc 运行时库(为了以后能安装其他工具); busybox 动态链接到 uclibc
1: 建立 cross toolchain
=======================
target 与 host 都是虚拟机, 架构是相同的(x86), 为何还需要 cross toolchain呢? 罪恶之源在uclibc: (1)用来build uclibc 的工具, 必须是built against uclibc的(见: http://www.uclibc.org/toolchains.html; 鸡->蛋->鸡->...); (2)用来build 与 uclibc 链接的程序的工具, 也必须是built against uclibc的; 而host上编译工具是链接到glibc的, 不符合这2个要求
利用buildroot工具来建造一个 cross toolchain
手工建造cross toolchain也是uclibc难搞
理论上, 用 buildroot 可以建造出我们最终想要的 target rootfs(uclibc + busybox + kernel + ...), 但是, 实践证明(theory vs. reality): (1)目标越大, 出问题的可能性越高; (2)自动化程度越高, 出了问题越难解决(花费额外时间解决自动化工具本身的问题; buildroot 的 make 系统的质量还比不上 kernel 或 gcc)
此外, 我也希望了解手工建立一个linux系统的过程. 因此, 我这里只是用buildroot建立一个最简化的toolchain(uclibc+gcc+binutils+kernel headers(?)), 不包含任何其它工具. 如果以后需要其它的工具, 可以用这个 toolchain 自己 build, 即使有问题, 也可各个击破
v4@elws:~/toy$ tar xjvf ../tarballs/buildroot-2010.11.tar.bz2 -C .
v4@elws:~/toy$ cd buildroot-2010.11/
v4@elws:~/toy/buildroot-2010.11$ make distclean
v4@elws:~/toy/buildroot-2010.11$ make allnoconfig # 只需要 toolchain
v4@elws:~/toy/buildroot-2010.11$ make menuconfig
-> Target Architecture: 选i386
-> Target Architecture Variant: 选pentium pro
-> Toolchain: 选择 Build/install c++ compiler and libstdc++?
v4@elws:~/toy/buildroot-2010.11$ make source # 提前下载所需软件包buildroot 把自动下载的软件包放在 dl/ 目录. gcc, uclibc 等比较慢, 可以自己提前下载对应版本的放到 dl/ 下. 我总结的 buildroot-2010.11 对应的软件包及版本号(不完全):
- gcc-4.3.5.tar.bz2
- uClibc-0.9.31.tar.bz2
- linux-2.6.36.1.tar.bz2
- gmp-4.2.4.tar.bz2
- mpfr-2.4.1.tar.bz2
- binutils-2.20.1.tar.bz2
v4@elws:~/toy/buildroot-2010.11$ make uclibc-menuconfiguclibc配置保存在 output/toolchain/uClibc-0.9.31/.config
uclibc很可能以后还需要重新配置(缺少某些功能没有选择), 需要回到这里重复开始
-> Target Architecture Features and Options
-> Target x86 Processor Family 选Pentium-Pro
v4@elws:~/toy/buildroot-2010.11$ cp output/toolchain/uClibc-0.9.31/.config toolchain/uClibc/uClibc-0.9.31.configbuildroot 使用的uclibc配置为 toolchain/uClibc/uClibc-0.9.31.config (通过make menuconfig 查看/修改)
v4@elws:~/toy/buildroot-2010.11$ makemake 一次要很久(更糟糕的是: 有时, 重复make时, buildroot会再次下载已经下载过的软件包, 这对身在大国的网络用户来说是一个噩梦)(足够洗个热水澡->出去跑一圈->再洗个热水澡:<) 生成的cross toolchain 在 output/staging(不是output/toolchain, 参考 http://buildroot.uclibc.org/buildroot.html#using)
- c 头文件: output/staging/usr/include (包含 linux 头文件!)
- 库文件: output/staging/usr/lib
- 工具: output/staging/usr/bin/i686-linux-{gcc, ld, strip...}
=================
build kernel 要小心的是使用cross toolchain
v4@elws:~/toy$ tar xjvf buildroot-2010.11/dl/linux-2.6.36.1.tar.bz2 -C .内核版本最好与buildroot 使用的一致. 这里直接使用buildroot下载的
v4@elws:~/toy$ cd linux-2.6.36.1/修改 Makefile 中这一行: EXTRAVERSION = .1-toy-1.0
v4@elws:~/toy/linux-2.6.36.1$ make mrproper
v4@elws:~/toy/linux-2.6.36.1$ make ARCH=x86 allnoconfig # 从零开始kernel支持的架构在arch/目录下. 这里其实可以省略 ARCH=...
v4@elws:~/toy/linux-2.6.36.1$ make ARCH=x86 menuconfig选择:
-> Processor type and features计划在target 硬盘上建立 ext3 文件系统, 因此kernel要支持 ext3
-> Processor family(选 Processor family, 默认已选中)
Generic x86 support
-> File systems硬盘为scsi, 要支持pci, scsi
-> Ext3 journalling file system support
-> Bus options (PCI etc.)
-> PCI support
PCI Express support
-> Device Drivers
-> SCSI device support
SCSI disk support
-> Device Drivers接下来的部分比较 tricky(提前公布谜底): host 与 target 都是虚拟机, 它们硬件架构是相同的. 在 host 执行 lspci 命令, 关于 scsi 控制器的输出为
-> Block devices
00:10.0 SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)说明 scsi 控制器采用了 Fusion 架构. linux 要从 Fusion 设备上启动, 必须在内核内建 Fusion 驱动
-> Device Drivers顺便启用DMA
-> Fusion MPT device support
-> Fusion MPT ScsiHost drivers for SPI
-> Device Drivers另外, 要启用 ELF 支持, 否则kernel 启动后将不能执行任何程序! (提前公布谜底. 我通过失败得来)
-> DMA Engine support
-> Executable file formats / Emulations保存配置后开始编译
-> Kernel support for ELF binaries
v4@elws:~/toy/linux-2.6.36.1$ make ARCH=x86 CROSS_COMPILE=$HOME/toy/buildroot-2010.11/output/staging/usr/bin/i686-linux-kernel 编译一般不会出什么问题, 因为 kernel 不依赖于任何外部库(但是编译过程中要使用一些工具, 如 perl)
10分钟左右编译完, 生成的kernel为 arch/x86/boot/bzImage
3: boot kernel
=================
接下来在target硬盘上建立文件系统, 安装grub和kernel
下面的操作以root执行
elws:~# fdisk /dev/sdd # 在target 硬盘上划分一个主分区可以给grub设置一下启动菜单, 免得以后启动target手动输入启动参数
elws:~# mke2fs -j /dev/sdd1
elws:~# mkdir -p /mnt/toy/
elws:~# mount /dev/sdd1 /mnt/toy/
elws:~# grub-install --root-directory=/mnt/toy/ /dev/sdd
elws:~# vi /mnt/toy/boot/grub/menu.lst输入其内容为:
default 0把kernel 拷贝到 target 硬盘
timeout 5
title toy linux
root (hd0,0)
kernel /boot/bzImage rw root=/dev/sda1
elws:~# cp /home/v4/toy/linux-2.6.36.1/arch/i386/boot/bzImage /mnt/toy/boot/现在可以关闭host(target 硬盘还挂在host上), 启动 target. 如果前面一切正常, kernel 应该可以挂载根分区, 然后到运行 init 时 kernel panic, 如下:
4: build busybox
===============
使用cross toolchain 来 build busybox
v4@elws:~/toy$ tar xjvf ../tarballs/busybox-1.18.1.tar.bz2 -C .
v4@elws:~/toy$ cd busybox-1.18.1/
v4@elws:~/toy/busybox-1.18.1$ make defconfig
v4@elws:~/toy/busybox-1.18.1$ make menuconfig
-> Busybox Settings
-> Build Options
-> Build BusyBox as a static binary (no shared libs) 不要选择(默认不选择)
-> Busybox Settings填: /home/v4/toy/buildroot-2010.11/output/staging/usr/bin/i686-linux-
-> Build Options
-> Cross Compiler prefix
v4@elws:~/toy/busybox-1.18.1$ make如果编译成功: (如果出错了, 看本节末尾的错误记录)
v4@elws:~/toy/busybox-1.18.1$ make installbusybox 安装在 _install/
编译过程中可能出错, 记录如下
(1)
In file included from /home/v4/toy/buildroot-2010.11/output/staging/usr/include/limits.h:27,解决:(先后顺序重要! 如果buildroot不支持, uclibc也不会支持)
from /home/v4/toy/buildroot-2010.11/output/staging/usr/lib/gcc/i686-unknown-linux-uclibc/4.3.5/include-fixed/limits.h:122,
from /home/v4/toy/buildroot-2010.11/output/staging/usr/lib/gcc/i686-unknown-linux-uclibc/4.3.5/include-fixed/syslimits.h:7,
from /home/v4/toy/buildroot-2010.11/output/staging/usr/lib/gcc/i686-unknown-linux-uclibc/4.3.5/include-fixed/limits.h:11,
from include/platform.h:153,
from include/libbb.h:13,
from include/busybox.h:10,
from applets/applets.c:9:
/home/v4/toy/buildroot-2010.11/output/staging/usr/include/features.h:216:5: error: #error It appears you have defined _FILE_OFFSET_BITS=64. Unfortunately, uClibc was built without large file support enabled.
重新配置buildroot, 添加LFS
-> Toolchain重新配置uclibc, 添加Large File Support (LFS)
-> Enable large file (files > 2 GB) support?
-> General Library Settings(2)
-> Large File Support
networking/inetd.c:163:21: error: rpc/rpc.h: No such file or directory解决: (顺序重要!)
给buildroot增加rpc支持:
-> Toolchain需要给uclibc增加rpc支持:
-> Enable IPv6
Enable RPC
-> Networking Support5: 启动到 sh# 提示符
-> Remote Procedure Call (RPC) support
IP version 6 support
Use netlink to query interfaces
==================
现在要将busybox以及uclibc运行时库安装到target
检查busybox需要的动态库:
v4@elws:~/toy$ buildroot-2010.11/output/staging/usr/bin/i686-linux-ldd busybox-1.18.1/_install/bin/busybox即: busybox 只依赖于libc.so, libm.so 和 ld-uClibc.so
checking sub-depends for 'not found'
checking sub-depends for 'not found'
libm.so.0 => not found (0x00000000)
libc.so.0 => not found (0x00000000)
/lib/ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x00000000)
(以下以root执行)
elws:~# mount /dev/sdd1 /mnt/toy/
elws:~# mkdir -p /mnt/toy/etc \
> /mnt/toy/etc/init.d \
> /mnt/toy/lib \
> /mnt/toy/proc \
> /mnt/toy/sys \
> /mnt/toy/dev \
>
elws:~# cd /home/v4/toy/buildroot-2010.11/output/target/lib/创建 busybox init 脚本:
elws:/home/v4/toy/buildroot-2010.11/output/target/lib# rsync -a ld-uClibc* libc.so.0 libuClibc-0.9.31.so libm* /mnt/toy/lib/
elws:/home/v4/toy/buildroot-2010.11/output/staging# cd
elws:~# rsync -a /home/v4/toy/busybox-1.18.1/_install/ /mnt/toy/
elws:~# sync
elws:~# vi /mnt/toy/etc/inittab输入以下内容:
# This is run first script创建系统启动时运行的脚本(系统初始化):
::sysinit:/etc/init.d/rcS
# Start an "askfirst" shell on the console
::askfirst:-/bin/sh
# Stuff to do when restarting the init process
::restart:/sbin/init
# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
elws:~# mkdir -p /mnt/toy/etc/init.d在启动脚本中mount 虚拟文件系统:
elws:~# vi /mnt/toy/etc/init.d/rcS
#!/bin/sh创建 /dev/console, null 2个设备节点(否则, target kernel 启动后, shell 的输出不显示在屏幕上):
mount -t proc none /proc
mount -t sysfs none /sys
elws:~# mkdir -p /mnt/toy/dev(注: 可通过在 host 上 ls -l /dev/xyz 查看节点号)
elws:~# mknod /mnt/toy/dev/console c 5 1
elws:~# mknod /mnt/toy/dev/null c 1 3
修改文件权限:
elws:~# cd /mnt/toy/关闭host, 启动 target:
elws:/mnt/toy# chown -R root:root .
elws:/mnt/toy# chmod +x etc/init.d/rcS
6: TODO
============
现在已经建造了一个最基本的linux系统, rootfs 大小为2.3MB:
elws:/mnt# du -sh toy/通过细致地精简busybox及uclibc, 还可较大幅度减小. 接下来要做:
2.3M toy/
- acpi 电源管理. 目前 halt 后, 虚拟机电源没有切断
- tcp/ip 网络支持
- 启用 framebuffer, 获得图形控制台(以及企鹅logo!)
No comments:
Post a Comment