FreeBSD Kernel-编译环境搭建
0 概述
本文章介绍一个搭建基于Qemu的FreeBSD虚拟机、在Linux下交叉编译FreeBSD内核并替换FreeBSD内核的开发环境。
1 文件准备
我把以下的步骤都打包为一个docker image:yirannn/modular-os-env,如果你使用该镜像,可以略过文件准备部分
1.1 FreeBSD SRC
你可以在官方网站或者科大镜像下载你需要的文件,其中src.txz为FreeBSD的源码
1.2 FreeBSD QCOW2
你可以在官方网站或者科大镜像下载qemu可用的qcow2文件,用于作为替换内核的基础镜像
1.3 编译软件包
下载好文件后,你可以选择参照我的镜像Dockerfile来安装软件包。
apt-get install qemu-system wget bmake gcc g++ clang-14 lld-14 libarchive-dev
1.4 启动Docker
docker run -it --name modular-os-zswap --privileged=true yirannn/modular-os-env bash
如果出现 mount无权限、qemu无kvm,首先怀疑是不是privileged没打开
2 编译
2.1 编译命令的来源
FreeBSD的源码并未直接准备好在Linux下编译,但是在FreeBSD 13之后,官方开始在macOS、Linux下进行交叉编译,并提供了Github CI进行验证。我在Action中翻到了相关的编译命令,仿照相关命令进行编译。这意味着我其实并不知道每一步具体都干了什么,如果你对此有疑问,建议可以自行查阅FreeBSD的Github Action
name: Cross-build Kernel
on:
push:
branches: [ main, 'stable/13' ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
name: ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
target_arch: [ amd64, aarch64 ]
os: [ ubuntu-20.04, ubuntu-22.04, macos-latest ]
include:
# TODO: both Ubuntu and macOS have bmake packages, we should try them instead of bootstrapping our own copy.
- os: ubuntu-20.04
compiler: clang-12
cross-bindir: /usr/lib/llvm-12/bin
pkgs: bmake libarchive-dev clang-12 lld-12
- os: ubuntu-22.04
compiler: clang-14
cross-bindir: /usr/lib/llvm-14/bin
pkgs: bmake libarchive-dev clang-14 lld-14
- os: macos-latest
compiler: clang-13
cross-bindir: /usr/local/opt/llvm@13/bin
pkgs: bmake libarchive llvm@13
- target_arch: amd64
target: amd64
- target_arch: aarch64
target: arm64
steps:
- uses: actions/checkout@v3
- name: install packages (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update --quiet || true
sudo apt-get -yq --no-install-suggests --no-install-recommends install ${{ matrix.pkgs }}
- name: install packages (macOS)
if: runner.os == 'macOS'
run: |
brew update --quiet || true
brew install ${{ matrix.pkgs }} || true
- name: create environment
run: |
echo "GITHUB_WORKSPACE = $GITHUB_WORKSPACE"
if [ -n "${{ matrix.cross-bindir }}" ]; then
echo "EXTRA_BUILD_ARGS=--cross-bindir=${{ matrix.cross-bindir }}" >> $GITHUB_ENV
fi
mkdir -p ../build
echo "MAKEOBJDIRPREFIX=${PWD%/*}/build" >> $GITHUB_ENV
# heh, works on Linux/BSD/macOS ...
echo "NPROC=`getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1`" >> $GITHUB_ENV
- name: bootstrap bmake
run: ./tools/build/make.py --debug $EXTRA_BUILD_ARGS TARGET=${{ matrix.target }} TARGET_ARCH=${{ matrix.target_arch }} -n
- name: make kernel-toolchain
run: ./tools/build/make.py --debug $EXTRA_BUILD_ARGS TARGET=${{ matrix.target }} TARGET_ARCH=${{ matrix.target_arch }} kernel-toolchain -s -j$NPROC -DWITH_DISK_IMAGE_TOOLS_BOOTSTRAP
- name: make buildkernel
run: ./tools/build/make.py --debug $EXTRA_BUILD_ARGS TARGET=${{ matrix.target }} TARGET_ARCH=${{ matrix.target_arch }} KERNCONF=GENERIC NO_MODULES=yes buildkernel -s -j$NPROC $EXTRA_MAKE_ARGS
2.2 编译
FreeBSD的编译需要几个环境变量,我们构建如下的目录结构
parent --|-- src
| |--- tools --- build
|
|-- obj
并在parent目录下声明如下变量
export BASEDIR=$(pwd)
export MAKEOBJDIRPREFIX=$BASEDIR/obj
这之后,进入src目录,开始编译
cd $BASEDIR/src
# 进入src目录
./tools/build/make.py --debug --cross-bindir=/usr/lib/llvm-14/bin/ TARGET=amd64 TARGET_ARCH=amd64 -n
# Bootstrap
./tools/build/make.py --debug --cross-bindir=/usr/lib/llvm-14/bin/ TARGET=amd64 TARGET_ARCH=amd64 kernel-toolchain -s -j32 -DWITH_DISK_IMAGE_TOOLS_BOOTSTRAP
# Toolchain
./tools/build/make.py --debug --cross-bindir=/usr/lib/llvm-14/bin/ TARGET=amd64 TARGET_ARCH=amd64 KERNCONF=GENERIC NO_MODULES=yes buildkernel -s -j32
# Kernel
其中 cross-bindir 指示了用于交叉编译的编译器二进制文件存放目录,TARGET和TARGET_ARCH指示了交叉编译的目标系统架构,编译好的内核在 obj/root/source/freebsd/src/amd64.amd64/sys/GENERIC/kernel.full
3 内核替换
3.1 准备共享区
共享区是为了把宿主机编译好的 kernel.full 传递给 qemu 启动的虚拟机
首先创建一块4M*1K的虚拟磁盘,用ext4格式化
dd if=/dev/zero of=/opt/share.img bs=4M count=1k
mkfs.ext4 /opt/share.img
创建一个目录,把该虚拟磁盘文件挂到该目录,并把编译好的内核放在该目录中
如果 mount 无权限,但已经在超级用户权限下了,考虑是否容器启动没有priviledged
mkdir /tmp/share
mount -o loop /opt/share.img /tmp/share
cp $BASEDIR/obj/root/source/freebsd/src/amd64.amd64/sys/GENERIC/kernel.full /tmp/share
3.2 准备虚拟机
3.2.1 启动虚拟机
在第一步骤中已经下载好了qcow2在本步骤中我们进行一个使用
unxz FreeBSD-12.4-RELEASE-amd64.qcow2.xz
qemu-img resize FreeBSD-12.4-RELEASE-amd64.qcow2 +1G
# 调整镜像大小,如果不调整,后续无法安装软件包
这之后,使用qemu启动FreeBSD
qemu-system-x86_64 -drive file=FreeBSD-12.4-RELEASE-amd64.qcow2,format=qcow2 -enable-kvm -hdb /opt/share.img
目前qemu启动FreeBSD还必须用一个图形界面,如果使用-nographic 选项,会导致FreeBSD无法正常Boot
这之后,使用root用户登录,没有密码
输入uname -a
查看内核版本,可以看到我们加载的是 FreeBSD 12.4
接下来挂载我们刚刚准备好的共享区
pkg install sysutils/fusefs-ext2
这一步需要按两次y,并有可能出现磁盘空间不足的问题。这可能是由于前步未执行扩展qcow2指令导致的
3.2.2 如果空间不足怎么办
关闭虚拟机,回到宿主机,尝试扩展qcow2文件
qemu-img resize FreeBSD-12.4-RELEASE-amd64.qcow2 +1G
重新用刚刚的命令启动qemu,在FreeBSD中
gpart show
可以看到freebsd-ufs的空间情况和分区号
使用gpart扩展ufs分区
gpart resize -i 4 -a 4k -s 5G ada0
growfs /dev/gpt/rootfs
重新安装fusefs-ext2模块
3.2.3 挂载
使用camcontrol命令查看当前系统的硬件设备
第一块盘ada0是启动的系统盘,第二块是我们在qemu中用hdb参数挂上去的共享盘
用fuse-ext2对这个盘进行映射
kldload fuse.ko # 如果不注册,每次用都得加载一下
mkdir /share
fuse-ext2 /dev/ada1 /share
ls /share
把kernel替换掉
cd /boot/kernel
mv kernel kernel.old
cp /share/kernel.full ./kernel
reboot
等待系统重启,重新uname -a
此时可以看到内核已经更新到我们编译的13.2
评论 (0)