一、准备内核
转载:https://zhuanlan.zhihu.com/p/27009845
首先要有一个能用的 Linux 宿主机,我使用的是 Ubuntu 16.04。然后安装好编译时候用到的库和软件包,由于我的 Ubuntu 16.04 是使用过一段时间的,可能有一些软件包或者库我之前已经装过了,所以没有列举出来,下面是一些我能想到的,其它我没有想到的可以直接把错误信息放进百度,查找缺少的包的信息然后再安装。打开命令行,输入:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libncurses5-dev libncursesw5-dev
sudo apt-get install ncurses-devel
sudo apt-get install gcc
sudo apt-get install vim
sudo apt-get install wget
在普通用户下输入
cd ~
进入用户目录,输入
wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.11.1.tar.xz
等待进度条走到 100%,此时一个完整的 linux 内核源码包就放在你的用户目录下。输入
xz -d linux-4.11.1.tar.xz
tar xvf linux-4.11.1.tar
cd linux-4.11.1
这样一个解压好的源码包就放在了用户目录下。
二、编译配置内核
此时确认在内核目录下,输入
pwd
显示
/home/song/linux-4.11.1
输入
make x86_64_defconfig
make menuconfig
会出现一个窗口
把第二项 Enable Loadable module support 取消掉,把 Networking support 取消掉。
然后选中 Device Devices(设备驱动) -> Block devices 下的 loopback device support, RAMblock device support
选择Device Devices->SCSI Support 下的 SCSI device support 下的SCSI disk Support、 SCSI low-level drivers ---> Buslogic SCSI support
选择Device Devices->USB Support 下的Support for Host-side USB,Preliminary USB device filesystem ,USB Mass Storage support。另外,还需要选EHCI HCD (USB 2.0) support。Preliminary USB device filesystem 没找到这个选项
然后输入 make bzImage
编译过程十分漫长,看个电影再说吧、需要的内存也很大。
linux-4.11.1 file arch/x86/boot/bzImage
arch/x86/boot/bzImage: Linux kernel x86 boot executable bzImage, version 4.11.1 (song@song) #1 SMP Sat May 20 12:41:40 CST 2017, RO-rootFS, swap_dev 0x4, Normal VGA
3.准备 BusyBox工具
命令行输入
wget https://busybox.net/downloads/busybox-1.26.2.tar.bz2
下载完成之后输入
tar -jxvf busybox-1.26.2.tar.bz2
cd busybox-1.26.2/
在命令行输入
make defconfig
make menuconfig
开始配置将一些必要的选项打[*]或[ ]:
BusyBox Setting->Build Options->[*]Build Busybox as a static binary (no shared libs)
BusyBox Setting->Shells->chose your default shell(ash):
[*]ash
编译BusyBox,命令行输入 make
成功提示
LINK busybox_unstripped
Static linking against glibc, can't use --gc-sections
Trying libraries: crypt m
Library crypt is not needed, excluding it
Library m is needed, can't exclude it (yet)
Final link with: m
DOC busybox.pod
DOC BusyBox.txt
DOC busybox.1
DOC BusyBox.html
安装BusyBox,命令如下:
make install
执行完后会产生_install/bin/ 和_install/sbin/后面会用到这些文件
部分提示:
busybox-1.26.2 make install
./_install//bin/ash -> busybox
./_install//bin/base64 -> busybox
./_install//bin/cat -> busybox
./_install//bin/catv -> busybox
./_install//bin/chattr -> busybox
./_install//bin/chgrp -> busybox
./_install//bin/chmod -> busybox
./_install//bin/chown -> busybox
./_install//bin/conspy -> busybox
./_install//bin/cp -> busybox
./_install//bin/cpio -> busybox
./_install//bin/cttyhack -> busybox
./_install//bin/date -> busybox
./_install//bin/dd -> busybox
./_install//bin/df -> busybox
./_install//bin/dmesg -> busybox
./_install//bin/dnsdomainname -> busybox
./_install//bin/dumpkmap -> busybox
./_install//bin/echo -> busybox
./_install//bin/ed -> busybox
./_install//bin/egrep -> busybox
./_install//bin/false -> busybox
ls 下会发现多了一个 _install 目录,里面是bin、sbin和usr,我们要用它来构建linux的根目录。
4.无盘 linux 的运行准备
首先在用户目录下新建一个文件夹romfs,然后把_install目录中的内容全部复制到romfs中。
➜ busybox-1.26.2 cd ~
➜ ~ pwd
/home/song
➜ ~ mkdir romfs
➜ ~ cp -r busybox-1.26.2/_install/* romfs/
现在rootfs下已经有了bin、sbin、usr目录,好像还缺什么。现在来添加:
➜ romfs mkdir proc mnt var tmp dev sys etc
同时在romfs下还必须要有一个init文件,这个init文件可以是一个可执行的二进制文件,也可以是一个shell脚本,或者是指向前面两者的链接。init文件会在linux内核初始化就绪后被执行。方便起见,我们就把init做成一个指向bin/sh的软连接:
➜ ~ cd romfs/
➜ romfs ln -s bin/sh init
dev目录下还必须有几个必要的设备console,null,tty,tty1,tty2,tty3,tty4:
➜ romfs cd dev/
➜ dev sudo mknod console c 5 1
➜ dev sudo mknod null c 1 3
➜ dev sudo mknod tty c 5 0
➜ dev sudo mknod tty1 c 4 1
➜ dev sudo mknod tty2 c 4 2
➜ dev sudo mknod tty3 c 4 3
➜ dev sudo mknod tty4 c 4 4
这些tty就是和用户交互的终端。
制作 压缩镜像。
➜ dev cd ~/romfs/
➜ romfs find . | cpio -H newc -o > ../romfs.img
5157 块
➜ romfs cd ../
➜ ~ gzip romfs.img -f
5.在优盘上建立根文件系统
5.1 在优盘上建立Linux分区和ext3文件格式
把优盘插入物理机,在vmware右下角,点击优盘图标选择连接主机
打开命令行,输入
sudo fdisk -l
优盘设备为 /dev/sdb1
格式化优盘,命令行输入
sudo fdisk /dev/sdb
出现
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
命令(输入 m 获取帮助):
输入 d 删除原来的分区,原来有几个分区就输入几次d。直到出现 No partition is defined yet!
命令(输入 m 获取帮助): d
Selected partition 1
Partition 1 has been deleted.
命令(输入 m 获取帮助): d
No partition is defined yet!
Could not delete partition 1
输入n 建立新的分区
命令(输入 m 获取帮助): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p):
输入 p
Select (default p): p
分区号 (1-4, default 1):
输入 1
分区号 (1-4, default 1): 1
First sector (2048-30218841, default 2048):
剩下的回车默认
First sector (2048-30218841, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-30218841, default 30218841):
Created a new partition 1 of type 'Linux' and of size 14.4 GiB.
命令(输入 m 获取帮助):
输入p查看是否分区成功
命令(输入 m 获取帮助): p
Disk /dev/sdb: 14.4 GiB, 15472047104 bytes, 30218842 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x35ca5e88
设备 启动 Start 末尾 扇区 Size Id 类型
/dev/sdb1 2048 30218841 30216794 14.4G 83 Linux
命令(输入 m 获取帮助):
输入w保存退出
命令(输入 m 获取帮助): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
输入
ls /dev | grep sd
可以看到有了 sdb1,这是我们要装系统用的分区,下面格式化分区,制作文件系统。
mkfs.ext3 /dev/sdb1
➜ ~ sudo mkfs.ext3 /dev/sdb1
mke2fs 1.42.13 (17-May-2015)
/dev/sdb1 contains a ext2 file system
last mounted on /media/song/d96c0389-5965-453f-8091-39a778eb778f on Sat May 20 15:01:03 2017
无论如何也要继续? (y,n) y
Creating filesystem with 3777099 4k blocks and 944704 inodes
Filesystem UUID: db1cf942-3250-439b-a1ef-773104282c01
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208
Allocating group tables: 完成
正在写入inode表: 完成
Creating journal (32768 blocks): 完成
Writing superblocks and filesystem accounting information: 完成
然后可以把U盘挂载入文件系统,进行文件操作。
sudo mkdir /mnt/usb
sudo mount /dev/sdb1 /mnt/usb
linux 要想启动,还需要一个类似bootloader的程序,它负责解压并复制initrd到内存指定的位置,和解压并复制内核到内存的指定位置,然后jump到内核的入口地址,并告诉内核initrd在哪里。它通常分为两个部分。
第一部分是一个短于512字节的代码,这一段代码被放在磁盘的第一个扇区,也就是磁盘能够读写的部分的前512字节,这512字节被称作引导区。这512字节内,除了bootloader的代码外,还有64字节用来存放分区表,所以bootloader的代码更是少的可怜。这段代码做不了什么复杂的事情,就只包含一个极其简陋的硬盘驱动程序,找到这块磁盘上的bootloader的第二阶段的代码,复制第二阶段的代码到内存,然后jump到第二阶段的代码的入口地址,执行之。
第二阶段的代码就复杂多了,它包含各种硬件(尤其是硬盘)与文件系统的驱动程序。它建立一个较完善的文件系统,然后从文件系统中读取内核与initrd,然后运行内核。
在PC机上,最流行的bootloader就是grub。它的第一部分在引导区中,第二部分在/boot/grub/中。
安装 grub
sudo grub-install --root-directory=/mnt/usb /dev/sdb
➜ ~ sudo grub-install --root-directory=/mnt/usb /dev/sdb
Installing for i386-pc platform.
Installation finished. No error reported.
这条命令会把grub安装到/dev/sdb中,即把grub的第一阶段(短于512字节的部分)放入/dev/sdb的第一扇区,并且把第二阶段要用到的各种文件放到当前目录(即/dev/sdb1分区承载的ext3文件系统)(更准确的说,是放在了/dev/sdb1/boot/grub,即/root/udisk/boot/grub目录下)。
然后再把过去做好的bzImage和rootfs.img.gz复制到udisk的boot目录下
➜ ~ sudo cp linux-4.11.1/arch/x86/boot/bzImage /mnt/usb/boot/
➜ ~ sudo cp romfs.img.gz /mnt/usb/boot/
最后就是编辑一下grub.conf配置文件:
sudo vim /mnt/usb/boot/grub/grub.cfg
输入
menuentry "songwenshuai-linux" {
set root='hd0,msdos1'
linux /boot/bzImage root=/dev/ram
initrd /boot/romfs.img.gz
}
保存后,卸载U盘:
sudo umount /mnt/usb
拔出优盘制作成功。
更改 bios 的 boot让它从优盘启动。
结果
遇到的关键问题:
最开始的 grub.cfg 中的
set root='hd0,msdos1'
配置错误,在 grub 下输入 ls
得到正确信息改正后运行正确。
转载注明出处