计算机:操作系统的知识

3 minute read

Published:

操作系统,操作系统内核那些事儿

Linux kernel 编译

前置准备

  1. linux 环境

  2. 源码位置:

    • 进入 https://www.kernel.org/,或者搜索 Linux kernel 找到这个
    • 使用 git 下载的话就点击 git:https://git.kernel.org/
    • 有很多 repo,从里面搜索 Torvalds,找到kernel/git/torvalds/linux.git
    • 点进去下方就有下载方式,git clone 或者 wget *.tar.gz 都可以,推荐 wget,源码特别大
  3. busybox

    • 用户空间的工具集,否则启动之后没有任何工具可以使用
    • 链接:https://www.busybox.net/
    • git clone,或者 wget *.tar.bz2:wget https://busybox.net/downloads/busybox-1.37.0.tar.bz2

开始编译

  1. 编译 kernel

    • make defconfig
    • (optional)make menuconfig
    • make -j$(nproc)
    • 编译产物会显示:./arch/x86_64/boot/bzImage
  2. 编译 busybox

    • 从源码编译
    • make defconfig
    • make nemuconfig
    • 打开:Settings —> Build static binary (no shared libs)
    • 关闭:Networking Utilities —> tc (8.3 kb)
    • make -j$(nproc)
    • make install
  3. 打包 initramfiles

    • mkdir rootfs
    • cp -r busybox-1.37.0/_install/* rootfs/
    • vim init,内容如下
      • #!/bin/sh
      • echo “hello masteryi! this is your initramfs!”
      • /bin/sh
    • chmod +x init
    • find . | cpio -o -H newc | gzip > ../initramfs.cpio.gz

使用 qemu 仿真

  1. 使用 qemu 仿真

    • sudo apt install qemu-system-x86
    • qemu-system-x86_64 -kernel linux-6.16-rc2/arch/x86_64/boot/bzImage -initrd initramfs.cpio.gz -nographic -append “console=ttyS0”
    • 可以看到日志出现了“hello masteryi! this is your initramfs!”
    • 使用ctrl+A, x退出 qemu

替换 WSL 的内核

  1. 将编译好的 vmlinux 拷贝到 Windows 下的路径

  2. 设置.wslconfig,这一步只替换 kernel,不影响发行版

    • 查看状态,running的话关机
    • wsl -l -v
    • wsl –shutdown
    • vim ~/.wslconfig
      • [wsl2]
      • kernel=D:\project\vmlinux
    • wsl -d ubuntu
  3. 查看 2 次的uname -a,发现 kernel 版本已经变了

替换 WSL 的用户空间

  1. 将 rootfs 打包:tar -zcvf ../initramfs.tar.gz .
  2. 拷贝到 Windows 下的路径
  3. wsl –import mylinux D:\project\wsl_mylinux D:\project\initramfs.tar.gz
  4. wsl -d mylinux

编译 ISO 镜像文件

  1. sudo apt install isolinux syslinux genisoimage
  2. make isoimage FDARGS=”initrd=../initramfs.cpio.gz console=ttyS0” FDINITRD=../initramfs.cpio.gz
  3. qemu-system-x86_64 -cdrom arch/x86/boot/image.iso -nographic

编译 hd 镜像文件

和编译 ISO 基本是一样的

  1. sudo apt install ovmf(安装了还是找不到*** Need a shell.efi file for x64, please install EDK2/OVMF.)
  2. make hdimage FDARGS=”initrd=../initramfs.cpio.gz console=ttyS0” FDINITRD=../initramfs.cpio.gz
  3. qemu-system-x86_64 -hda arch/x86/boot/hdimage -nographic

但是安装 ovmf 后还是没有 shell.efi 这个东西,似乎是 ubuntu 的已知问题,于是源码下载,发现 master 分支没有这个文件,只能通过已有的 release 链接下载:

  • wget https://github.com/tianocore/edk2/blob/UDK2018/ShellBinPkg/UefiShell/X64/Shell.efi(无效)
  • wget https://github.com/tianocore/edk2/raw/UDK2018/ShellBinPkg/UefiShell/X64/Shell.efi

GitHub 的 blob URL 会返回一个 HTML 页面(包含代码渲染),而不是二进制文件 Shell.efi。所以下载还是要用 raw 的。

  • sudo cp Shell.efi /usr/share/OVMF

但是编译好 hdimage 后,还是无法通过 qemu 来测试,因为没有 bootloader,需要自己制作。直接使用 qemu 就会出现 Boot failed: not a bootable disk 的问题。

具体的制作脚本可以参考:https://github.com/masteryi-0018/software-notes/blob/main/shell/test.sh

通过qemu-system-x86_64 -hda hd.img --nographic成功启动!但是话说回来,其实并没有 hdimage 什么事。

编译 seabios

  • git clone https://git.seabios.org/seabios.git(这个比较慢)
  • git clone git@github.com:coreboot/seabios.git(github 镜像,快一些)
  1. 命令

    • cd seabios
    • make
    • qemu-system-x86_64 -bios out/bios.bin –nographic

这时候就可以用自己的 bios 和自己制作的带有 bootloader 的 linux os 来测试了:

  • qemu-system-x86_64 -hda hd.img -bios seabios/out/bios.bin –nographic

问题

  1. 为什么不能 apt install busybox?如果这样安装的话,会有依赖本地的动态库:

    • $: ldd /usr/bin/busybox
    • linux-vdso.so.1 (0x00007fff0cff3000)
    • libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f8b0c435000)
    • libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8b0c243000)
    • /lib64/ld-linux-x86-64.so.2 (0x00007f8b0c514000)
  2. 为什么需要手动设置 busybox?如果动态链接,还是有一样的问题;tc 这个是头文件,我也懒得继续 debug 了

安装操作系统

也就是通常讲的装系统,普罗大众会接触到的概念。给一个电脑安装操作系统,或者重装操作系统,最通常的情况是制作 U 盘启动盘。我们一般在另一个可以运行的电脑上下载对应的操作系统,这里一般是 ISO,也就是镜像,这个镜像也不直接搞到对应电脑的硬盘中,所以我们用 U 盘是最省事的,但是这个 ISO 不能直接使用,需要将 U 盘制作为启动盘之后才可以使用。

启动盘的作用和以前使用光盘启动是类似的,只不过更加方便,直接将 ISO 解压到 U 盘不能用,因为这个引导程序(Bootloader)没有被放置在正确的位置上,导致无法被识别为一个操作系统。

在编译 linux kernel 的时候,有几个选项:

  1. fd(软盘)
  2. hd(硬盘)
  3. cdrom(光盘)

这里的 cdrom 会强制安装 bios 到 iso 中,也就是解压后能看到的isolinux.binisolinux.cfg,这个 bin 和 seabios 的 out.bin 不是一个概念的东西,bios.bin 会执行 isolinux.bin,相当于光盘的 Bootloader。

使用 qwmu 仿真的时候,也有几个对应的选项:

  1. kernel + initrd
  2. fda
  3. hda
  4. cdrom

这里 cdrom 就是对应光盘,现在使用较少,而 hd 就是对应硬盘,U 盘启动盘就是模拟硬盘的;又因为光盘和 U 盘天生不同,光盘是 ROM,在刻录时,ISO 镜像的引导信息会自动写入光盘的引导扇区,因此,只要直接刻录完整的系统 ISO 文件,光盘本身就具备启动能力。U 盘是 RAM,所以需要制作启动盘这一步。

给电脑安装

不论是 PC 或者笔记本,都属于 x86 架构的通用计算机,这里的通用基本是指拥有主板,cpu,gpu,内存,等组件的一个计算机。主板是哪个厂商的,主板上的 bios 芯片就是哪个厂商已经写好的烧录好的,我们可以制作操作系统启动盘,但也是由这个 bios 进行引导的,也就是我们控制了 bootloader,os 和 kernel 的部分。如果我们需要修改 bios,需要专门写一个 bios,并且通过烧录,移植到主板上面。

给手机安装

手机从概念上面讲,甚至是一个广义的嵌入式设备,我的理解就是以 SoC 为主导的主板高度集成,手机的 bios/uefi 也在 SoC 上只读,之后进入存储分区,开始 bootloader 以及 Android 的加载。但是手机厂商一般会将 bootloader 上锁,只有解锁了之后,才能有 root 权限,才能使用已有的 bios/uefi 安装自己的操作系统,很折腾。

给树莓派安装

计算机可以这么分:

  • 通用计算机:PC,笔记本
  • SBC(单板计算机):树莓派,nv jetson 等。有操作系统,实际上是一个微型计算机。
  • MCU(单片机):stm32,adruino。无操作系统,软件需要烧录运行

还有一些其他的:

  • fpga:Xilinx 的一些板子
  • pynq/zynq:也是 Xilinx 的,但是使用了 arm+fpga 的异构体系

树莓派可以安装官方的操作系统,也可以安装 ubuntu 等 linux 发行版,所以应该也可以安装自己编译的 linux 系统,但不同的是,树莓派也是基于 arm 的架构,和手机一样,基于 arm 架构没有传统意义的 bios/uefi,叫做 bootrom,但实际上也一样,以后也就用 bios 指代这个启动过程。

  1. 给树莓派安装自定义的linux os

    • 查看linux kernel支持的树莓派config,ls arch/arm/configs/*bcm*
    • 发现只有一个,安装依赖:sudo apt install gcc-aarch64-linux-gnu
    • make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
    • make -j$(proc)

之后会有一堆选项,推荐直接按着回车不放

  1. 使用qemu仿真

    • sudo apt install qemu-system-arm
    • qemu-system-arm -kernel arch/x86/boot/bzImage -machine raspi2 –nographic

但是卡住了,原因还未知

启动过程

  • 上电
  • BIOS/UEFI:烧录在主板 bios 芯片,执行 POST(硬件自检)等
  • bootloader:lilo/grub,位于 os 镜像中,执行加载 kernel
  • kernel:接管资源,执行 init 进程,暴露 shell 给用户