首发于编程随记

制作 U 盘 Linux

一、准备内核

首先要有一个能用的 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

得到正确信息改正后运行正确。

转载注明出处

编辑于 2017-05-22

文章被以下专栏收录