当前位置: 首页 > news >正文

Linux入门攻坚——32、Mini Linux制作

制作一个mini linux,需要对linux的启动流程很熟悉,这里又一次学习Linux的启动过程。

启动流程:
CentOS 6 / 5:
    POST -->BootSequence(BIOS) --> BootLoader --> kernel (ramdisk) --> rootfs --> /sbin/init
        然后就涉及编写服务脚本(centos5/6),或这编写upstart配置文件(centos6)
    对于ramdisk,是用于提供设备驱动的,主要是根文件系统的设备驱动,如果根文件系统所在设备的驱动编译进内核了,那么就不需要加载ramdisk了,凡是编译进内核的驱动,都可以直接使用其设备。而一般的,设备驱动不会直接编译进内核,主要是控制内核的大小,否则内核会很大。设备驱动编译成模块,按需加载。 
    对于/sbin/init,CentOS5是读取/etc/inittab配置文件,执行其中的配置,而CentOS6则是读取/etc/init/*.conf配置文件,执行其中的配置。这些配置文件要完成的功能:
    - 确定默认执行级别
    - 运行系统初始化脚本:/etc/rc.d/rc.sysinit
    - /etc/rc.d/rc $runlevel  
    - 启动终端,并运行login
    - 启动图形终端(运行级别5)
CentOS 7
    POST -->BootSequence(BIOS) --> BootLoader -->kernel (ramdisk) -->rootfs --> /sbin/systemd
         编写服务脚本
         systemd unit文件

总体来说,一个最基本的linux系统,就是引导设备上的MBR中的bootloader装载linux内核,然后切换根文件系统,最后启动init(或systemd)。

bootloader:    lilo、grub legacy、grub2
grub:stage1:mbr
           stage1_5:filesystem driver
           stage2:grub的各项加载选项等。

内核编译:
    make menuconfig   --> .config     (主要生成.config文件)
    make [ -j # ]            
    make modules_install    (安装模块)
    make install

Mini Linux制作步骤:
    bootloader:grub安装
    内核:  kernel(非模块方式,所有驱动编译进内核)  
    根文件系统:busybox  (模拟实现用户空间中的各种程序)

1、环境配置,编译内核需要安装“Development Tools”和“Server Platform Development”软件包组
2、下载内核源代码:www.kernel.org,测试下载了linux-4.19.321.tar.xz。
3、解压缩,tar xf linux-4.19.321.tar.xz -C /usr/src
      创建解压后目录的链接文件: ln -sv linux-4.19.321 linux

4、内核的配置,一般在安装完成的机器上都有,如:/boot/config-2.6.32-754.el6.x86_64,因为这里是测试做一个最精简的linux,一切由自己手动配置。
首先把内核可选择的特性全部关闭掉: make allnoconfig   

执行完毕后,会在当前目录下生成.config文件

要编译内核,需要提前了解硬件特性,如cpu、pci,尤其要注意硬盘接口

然后执行make menuconfig,对内核特性进行配置

64-bit kernel要选择,要编译成64位的内核系统;
Enable loadable module support 要选择,支持模块动态加载特性,进入子菜单:

Module unloading选上,支持模块动态卸载。
Processor type and features --->选择处理器型号、特性,即支持的CPU型号,进入子菜单

进入Processor family(Generic-x86-64)--->

Generic-x86-64,通用x86-64CPU,不知道的情况下,可以选择这一项

回退上级菜单,选择Symmetric multi-processing support ,CPU对称多处理器的支持(多核处理器)
然后是总线的配置,Bus options (PCI etc.)  ---> ,对PCI的配置,进入子菜单:

PCI support选中,会多出很多选项,默认就可以。

 Device Drivers  --->   设备驱动的配置,主要是硬盘驱动的配置

lspci命令查看我们的存储设备,是:SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)
选择:Fusion MPT device support  --->  的子菜单中对应我们自己的硬盘设备,但是子菜单中没有列出来:

因为是SCSI总线,先要启用SCSI特性,所以选择:  SCSI device support  ----   这一项启用,但是这一项进去全是空的:

需要返回上一级,选择:Enable the block layer  ----  ,然后下面的scsi特性才能出来。

不做选择,采用默认。然后回到Device Drivers  --->菜单,此时SCSI device support  --->  下显示:
选择: SCSI device support  ,会列出很多选项:

选择:SCSI disk support,退出,再次进行硬盘驱动的选择:

选择: Fusion MPT ScsiHost drivers for SPI 这一项。为了保证编译后运行正常,,将Fusion的其他三项都选上。
以上配置完后,就可以进行编译。
5、执行编译:make -j 4 bzImage ,编译成bz格式的内核。运行中,提示gcc版本过低,网上查询需要gcc4.8以上,而CentOS6是gcc4.4,所以下载低版本内核试一下:linux-3.19.tar.xz

其menuconfig配置项有所不同:

总的配置就是:先配置内核是64位的,然后配置动态加载模块支持,在其子菜单下选择可以动态卸载,其后配置块设备支持,再配置CPU,支持多核和选择CPU类型,再配置总线选项,配置PCI支持选项,最后设备驱动配置,先配置SCSI设备,支持SCSI disk,即scsi磁盘,然后是硬盘设备配置,这里是Fusion MPT device。这样一个最基本的Linux内核就算配置完成。

执行编译:make -j 4 bzImage 最后的结果显示如下:

生成的内核位置:arch/x86/boot/bzImage

6、配置新linux的安装位置,需要新增一块硬盘,将自定义的Mini Linux安装在这块硬盘上:
关闭当前系统,进行虚拟机设置:

添加后两块磁盘。启动系统。

7、查看磁盘信息,对磁盘进行分区和格式化
查看磁盘:fdisk -l /dev/sdb

对磁盘进行分区,对一个基本Linux,分区一般最少3个:boot分区,根(/)分区和swap分区,对于最精简的linux,swap可以不使用,所以,指定boot和根/分区就可以了。


进行分区格式化:mke2fs -t ext4 /dev/sdb1   、  mke2fs -t ext4 /dev/sdb2

8、挂载创建的分区到当前系统上。
mkdir /mnt/{boot,sysroot}
mount /dev/sdb1 /mnt/boot/

9、安装grub:grub-install --root-directory=/mnt  /dev/sdb

这里要注意的关键点是参数--root-directory=/mnt,而不是/mnt/boot,原因在Linux入门攻坚——16、Linux系统启动流程中分析过。

至此,grub安装完成,下一步复制内核。一般的内核都是/boot/vmlinuz-文件,我们的内核在上一步已经编译完成并生成,即/usr/src/linux/arch/x86/boot/bzImage,将其拷贝到要制作的mini linux的/boot下:cp /usr/src/linux/arch/x86/boot/bzImage /mnt/boot/bzImage

有了内核,还要编辑grub的启动配置菜单,创建/mnt/boot/grub/grub.conf:

关键点是这里的root(hd0,0)和root=/dev/sda2,在当前的机器上,我们的mini linux是安装在第二块硬盘上的,应该是hd1,0 和/dev/sdb2,为何改为了hd0和sda2呢?这是因为mini linux单独运行时,就是单独在第二块硬盘上,此时对mini linux只有一块硬盘,相应的系统就应该识别成第一块硬盘,即hd0,0和/dev/sda2

10、测试启动Mini Linux:
将编译机器关闭,在vmware中新建虚拟机:

启动新建的虚拟机:

启动后,就是一个光标在黑屏上闪烁,于是再下了一个linux-3.10.67版本,重新制作内核,再次运行:

提示没有加载根文件系统。设备已经能够识别了,即sda1和sda2,其上有文件系统(通俗讲就是已经格式化了),只是其上没有对应文件,这里提示不能挂载,是内核驱动不了文件系统。内核中没有添加文件系统模块,需要重新编译内核,使其能够驱动文件系统。设备驱动了,文件系统不能驱动。

11、重新编译内核,添加文件系统驱动。make menuconfig,进入File systems --->选项中


至少保证我们使用的文件系统ext4被选择。然后配置可执行文件格式:Executable file formats / Emulations  --->  

支持ELF和#!,即bash,配置好后重新编译:
编译后,重新将生成的内核bzImage拷贝到sdb1,即/mnt/boot上,关闭本机,重新启动Mini Linux:

此时显示ext文件系统已经可用,最后是init没有发现。

12、提供一个真正的根文件系统:
启动内核,挂载文件系统后,内核是如何加载init的?查看内核的源代码:init/main.c

可以看到,init的加载,内核依次找的位置为/sbin/init、  /etc/init、  /bin/init 、 /bin/sh,所以,只要存在/bin目录其下有sh,系统就能跑起来。

首先,完成一下根文件系统,现在看所谓根文件系统,就是在根文件系统所在分区下创建对应的文件目录结构:

然后将程序或命令拷贝到对应目录中,不但要拷贝程序文件,还要拷贝命令程序依赖的库文件,于是编写一个拷贝命令程序的脚本文件:

#!/bin/bash
#
target=/mnt/sysroot
[ -d $target ] || mkdir /mnt/sysrootread -p "A Command:" cmdlibcp() {for lib in $(ldd $1 | grep -o "[^[:space:]]*/lib[^[:space:]]*"); dolibdir=$(dirname $lib)[ -d $target$libdir ] || mkdir -p $target$libdir[ -f $target$lib ] || cp $lib $target$libdone
}while [ "$cmd" != "quit" ]; doif ! which $cmd &> /dev/null; thenread -p "No such command,enter again:" cmdcontinueficmd=$(which --skip-alias $cmd)cmddir=$(dirname $cmd)[ -d $target$cmddir ] || mkdir -p $target$cmddir[ -f $target$cmd ] || cp $cmd $target$cmdlibcp $cmdread -p "Another command(quit):" cmd
done

代码实现的功能,就是在当前系统中,先测试给定的命令是否存在,如果存在,将此命令以及此命令依赖的库文件对等的拷贝到新系统的对应位置,如/bin/ls拷贝到/mnt/sysroot/bin/ls

可以测试一下:chroot  /mnt/sysroot/ /bin/bash,将target作为根目录(运行其中的 /bin/sh )

chroot命令 用来在指定的根目录下运行指令。chroot,即 change root directory (更改root 目录)。在 linux 系统中,系统默认的目录结构都是以 / ,即是以根 (root) 开始的。而在使用 chroot 之后,系统的目录结构将以指定的位置作为 / 位置。
在经过 chroot 命令之后,系统读取到的目录和文件将不在是旧系统根下的而是新根下(即被指定的新的位置)的目录结构和文件,因此它带来的好处大致有以下3个:
1. 增加了系统的安全性,限制了用户的权力:
    在经过 chroot 之后,在新根下将访问不到旧系统的根目录结构和文件,这样就增强了系统的安全性。这个一般是在登录 (login) 前使用 chroot,以此达到用户不能访问一些特定的文件。
2. 建立一个与原系统隔离的系统目录结构,方便用户的开发:
    使用 chroot 后,系统读取的是新根下的目录和文件,这是一个与原系统根下文件不相关的目录结构。在这个新的环境中,可以用来测试软件的静态编译以及一些与系统不相关的独立开发。
3.  切换系统的根目录位置,引导 Linux 系统启动以及急救系统等:
    chroot 的作用就是切换系统的根位置,而这个作用最为明显的是在系统初始引导磁盘的处理过程中使用,从初始 RAM 磁盘 (initrd) 切换系统的根位置并执行真正的 init。另外,当系统出现一些问题时,我们也可以使用 chroot 来切换到一个临时的系统。

13、在重新启动Mini Linux前,修改grub.conf,明确告知内核init的具体位置:

重新启动Mini Linux,启动后:

键入回车键无反映,其他按键也没反映,问题是在编译内核时,键盘驱动没有配置上,也就是没有键盘驱动程序,无法使用键盘。于是要重新配置内核选项,将键盘等基本设备的驱动编译进内核。
make menuconfig  ,选择Device Drivers  ---> 菜单下的 Input device support  --->   :

选择: Keyboards  --->,将其选中,还可进入子菜单,选择详细键盘型号,默认AT标准键盘就可以。  

要支持鼠标,选中:Mouse interface 选项,然后是Mice选项,其下有详细鼠标类型,对于vmware虚拟机,模拟出来的鼠标是usb口的鼠标,所以还要配置usb的驱动:在Device Drivers  --->下有USB support  --->选项,选中,然后进入下一级选具体usb类型,先看本机的USB类型:

为了以防万一,将各个版本的都选上:

Mice子菜单在配置USB选项前后:

配置好后,再次编译:make -j 4  bzImage
14、再次重启Mini Linux:

可以看到,bash启动了。可以运行内置命令了。但是,正常的Linux启动的是init,可以编写一个init脚本,来模拟init:

添加一些工具程序:

需要修改grub.conf,将init=/bin/bash去掉,或改为init=/sbin/init,或者不修改,在启动时使用e选项,进行手动修改。再次启动时又出现了错误,init启动不成功,有关键的一步没有做,就是编写的/sbin/init没有赋予执行权限,chmod +x /mnt/sysroot/sbin/init,然后再次启动:

此时,init运行成功。但是在/dev下,没有相关设备,要挂载sda1到/boot下,找不到设备

对于/dev下的设备,是由udev发现并创建的,我们内核中没有编译udev。

15、重新配置内核配置选项,将udev编译进内核:make menuconfig,
Device Drivers  --->下的Generic Driver Options  ---> 选项下

此时/dev下内核识别出的设备都显示出来。
 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • C++内联函数inline
  • 基于SpringBoot+Vue+MySQL的智能物流管理系统
  • 【STL】priority_queue 基础,应用与操作
  • 2024java面试-软实力篇
  • MySQL之表内容的增删改查(含oracel 9i经典测试雇佣表下载)
  • Avalonia:自定义控件
  • Unity教程(十六)敌人攻击状态的实现
  • Spring IoC 注解 总结
  • GitLab 迁移并推送代码仓库
  • 2024永久激活版 Studio One 6 Pro for mac 音乐创作编辑软件 完美兼容
  • FortiGate硬件高级测试指南
  • 数据结构——“二叉搜索树”
  • 条件编译代码记录
  • React 项目中,如何实现有效的内存管理和防止内存泄漏?
  • 二叉树(下)
  • JavaScript 如何正确处理 Unicode 编码问题!
  • @jsonView过滤属性
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • Effective Java 笔记(一)
  • es6要点
  • IDEA常用插件整理
  • js继承的实现方法
  • laravel 用artisan创建自己的模板
  • Quartz初级教程
  • quasar-framework cnodejs社区
  • react 代码优化(一) ——事件处理
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 精彩代码 vue.js
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 微信小程序实战练习(仿五洲到家微信版)
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #QT(QCharts绘制曲线)
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (全注解开发)学习Spring-MVC的第三天
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (四) 虚拟摄像头vivi体验
  • (一)模式识别——基于SVM的道路分割实验(附资源)
  • (转)JAVA中的堆栈
  • .NET MVC 验证码
  • .NET 的程序集加载上下文
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .NET上SQLite的连接
  • .NET微信公众号开发-2.0创建自定义菜单
  • .sys文件乱码_python vscode输出乱码
  • 。。。。。
  • [\u4e00-\u9fa5] //匹配中文字符
  • [000-002-01].数据库调优相关学习
  • [001-03-007].第07节:Redis中的事务