Skip to content

Jvlegod/lfs-from-riscv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

1 环境搭建

全程建议给执行的用户目标权限. 这样后面就尽量别用 sudo, 容易出错.

sudo chown -R lfs:lfs $LFS/tools $LFS/sources $LFS/usr $LFS

如果没有创建该用户.

# 创建 lfs 组
sudo groupadd lfs
# 创建 lfs 用户并加入组,指定 bash 为 shell
sudo useradd -s /bin/bash -g lfs -m -k /dev/null lfs
# 给 lfs 用户设置密码
sudo passwd lfs

后期恢复权限.

sudo chown -R root:root $LFS/tools
sudo chown -R root:root $LFS/sources
sudo chown -R root:root $LFS/usr

安装 riscv64 所需要的模拟器.

sudo apt install qemu-user-static qemu-system-riscv64

安装编译工具链.

see more: https://github.com/riscv-collab/riscv-gnu-toolchain

sudo apt-get install gcc-riscv64-linux-gnu
sudo apt install autoconf automake autotools-dev curl python3 python3-pip 
sudo apt install libmpc-dev libmpfr-dev libgmp-dev gawk 
sudo apt install build-essential bison flex texinfo gperf libtool patchutils 
sudo apt install bc zlib1g-dev libexpat-dev ninja-build git cmake libglib2.0-dev
git clone https://github.com/riscv/riscv-gnu-toolchain
./configure --prefix=/opt/riscv
make

安装需要 LFS 的最小软件包集合.

wget -r -l1 --no-parent --no-directories --reject "index.html*" https://ftp.osuosl.org/pub/lfs/lfs-packages/12.2/

你的目录大概如下:

$ ls
acl-2.3.2.tar.xz                  e2fsprogs-1.47.1.tar.gz      gperf-3.1.tar.gz                 libpipeline-1.5.7.tar.gz  patch-2.7.6.tar.xz                  tcl8.6.14-html.tar.gz
attr-2.5.2.tar.gz                 elfutils-0.191.tar.bz2       grep-3.11.tar.xz                 libtool-2.4.7.tar.xz      perl-5.40.0.tar.xz                  tcl8.6.14-src.tar.gz
autoconf-2.72.tar.xz              expat-2.6.2.tar.xz           groff-1.23.0.tar.gz              libxcrypt-4.4.36.tar.xz   pkgconf-2.3.0.tar.xz                texinfo-7.1.tar.xz
automake-1.17.tar.xz              expect-5.45.4-gcc14-1.patch  grub-2.12.tar.xz                 linux-6.10.5.tar.xz       procps-ng-4.0.4.tar.xz              tzdata2024a.tar.gz
bash-5.2.32.tar.gz                expect5.45.4.tar.gz          gzip-1.13.tar.xz                 lz4-1.10.0.tar.gz         psmisc-23.7.tar.xz                  udev-lfs-20230818.tar.xz
bc-6.7.6.tar.xz                   extra.sh                     iana-etc-20240806.tar.gz         m4-1.4.19.tar.xz          python-3.12.5-docs-html.tar.bz2     util-linux-2.40.2.tar.xz
binutils-2.43.1.tar.xz            file-5.45.tar.gz             inetutils-2.5.tar.xz             make-4.4.1.tar.gz         Python-3.12.5.tar.xz                vim-9.1.0660.tar.gz
bison-3.8.2.tar.xz                findutils-4.10.0.tar.xz      intltool-0.51.0.tar.gz           man-db-2.12.1.tar.xz      readline-8.2.13.tar.gz              wget-list
bzip2-1.0.8-install_docs-1.patch  flex-2.6.4.tar.gz            iproute2-6.10.0.tar.xz           man-pages-6.9.1.tar.xz    sed-4.9.tar.xz                      wheel-0.44.0.tar.gz
bzip2-1.0.8.tar.gz                flit_core-3.9.0.tar.gz       jinja2-3.1.4.tar.gz              MarkupSafe-2.1.5.tar.gz   setuptools-72.2.0.tar.gz            XML-Parser-2.47.tar.gz
check-0.15.2.tar.gz               gawk-5.3.0.tar.xz            kbd-2.6.4-backspace-1.patch      md5sums                   shadow-4.16.0.tar.xz                xz-5.6.2.tar.xz
check.sh                          gcc-14.2.0.tar.xz            kbd-2.6.4.tar.xz                 meson-1.5.1.tar.gz        sysklogd-2.6.1.tar.gz               zlib-1.3.1.tar.gz
coreutils-9.5-i18n-2.patch        gdbm-1.24.tar.gz             kmod-33.tar.xz                   mpc-1.3.1.tar.gz          systemd-256.4.tar.gz                zstd-1.5.6.tar.gz
coreutils-9.5.tar.xz              gettext-0.22.5.tar.xz        less-661.tar.gz                  mpfr-4.2.1.tar.xz         systemd-man-pages-256.4.tar.xz
dbus-1.14.10.tar.xz               glibc-2.40-fhs-1.patch       lfs-bootscripts-20240825.tar.xz  ncurses-6.5.tar.gz        sysvinit-3.10-consolidated-1.patch
dejagnu-1.6.3.tar.gz              glibc-2.40.tar.xz            libcap-2.70.tar.xz               ninja-1.12.1.tar.gz       sysvinit-3.10.tar.xz
diffutils-3.10.tar.xz             gmp-6.3.0.tar.xz             libffi-3.4.6.tar.gz              openssl-3.3.1.tar.gz      tar-1.35.tar.xz

2 一些重要的环境变量

一些目录.

mkdir -p /mnt/lfs
mkdir $LFS/sources

重要的环境变量.

export LFS=/mnt/lfs
export SOURCES=$LFS/sources
export TOOLS=$LFS/tools
export PATH=$TOOLS/bin:$PATH

3 正式开始安装

3.1 binutils

安装 binutils. 这一套工具是帮助我们交叉编译的.

cp -ar binutils-2.43.1.tar.xz $SOURCES
cd $SOURCES
tar -xf binutils-2.43.1.tar.xz -C $SOURCES
cd binutils-2.43.1/
mkdir build
cd build
../configure --prefix=$LFS/tools --target=riscv64-unknown-linux-gnu --disable-nls --enable-gold --enable-ld=default
make
make install

3.2 linux-header

首先 pull 下 linux kernel.

make mrproper
make ARCH=riscv INSTALL_HDR_PATH=$LFS/usr headers_install

3.3 gcc stage1

tar -xf gcc-14.2.0.tar.xz
cd gcc-14.2.0
# 如果 gmp, mpfr, mpc 没有拉到 gcc, 则将他们拉过去.
cp gmp-6.3.0.tar.xz mpfr-4.2.1.tar.xz mpc-1.3.1.tar.gz $SOURCES/gcc-14.2.0/
tar -xf gmp-6.3.0.tar.xz
tar -xf mpfr-4.2.1.tar.xz
tar -xf mpc-1.3.1.tar.gz
mv -v gmp-6.3.0  gmp
mv -v mpfr-4.2.1 mpfr
mv -v mpc-1.3.1  mpc
mkdir -p build
cd build
../configure                                        \
    --target=riscv64-unknown-linux-gnu              \
    --prefix=$LFS/tools                             \
    --with-glibc-version=2.40                       \
    --with-sysroot=$LFS                             \
    --with-newlib                                   \
    --without-headers                               \
    --enable-default-pie                            \
    --enable-default-ssp                            \
    --disable-nls                                   \
    --disable-shared                                \
    --disable-multilib                              \
    --disable-threads                               \
    --disable-libatomic                             \
    --disable-libgomp                               \
    --disable-libquadmath                           \
    --disable-libssp                                \
    --disable-libvtv                                \
    --disable-libstdcxx                             \
    --enable-languages=c,c++
make -j$(nproc)
make install

3.4 glibc

cp -v glibc-2.40.tar.xz glibc-2.40-fhs-1.patch $SOURCES/
tar -xf glibc-2.40.tar.xz
cd glibc-2.40
patch -Np1 -i ../glibc-2.40-fhs-1.patch
mkdir build && cd build
# 这里 prefix=/usr 是正确的, prefix 在这里指定的是在目标机器运行时的预期位置
# 4.15 表示兼容的最低版本.
../configure                             \
      --prefix=/usr                      \
      --host=riscv64-unknown-linux-gnu   \
      --build=$(../scripts/config.guess) \
      --enable-kernel=4.15               \
      --with-headers=$LFS/usr/include    \
      --disable-soft-fp                  \
      libc_cv_slibdir=/usr/lib           \
      libc_cv_rtlddir=/usr/lib
make -j$(nproc)
make DESTDIR=$LFS install

此时会看见多出许多文件.

$ ls $LFS
etc  linux-6.18.5  sbin  sources  tools  usr  var

验证是否安装正确.

# 动态链接器
ls -l $LFS/usr/lib/ld-linux-riscv64*.so.1
# 标准 C
ls -l $LFS/usr/lib/libc.so.6
file $LFS/usr/lib/libc.so.6
# 头文件
ls -l $LFS/usr/include/stdio.h
# 验证动态链接器路径
grep 'RTLDLIST=' $LFS/usr/bin/ldd
# RTLDLIST="/usr/lib/ld-linux-riscv64-lp64.so.1 /usr/lib/ld-linux-riscv64-lp64d.so.1 /usr/lib/ld-linux-riscv32-ilp32.so.1 /usr/lib/ld-linux-riscv32-ilp32d.so.1"

现在来验证一下程序.

echo '#include <stdio.h>
int main() { printf("Hello, RISC-V!\n"); return 0; }' > hello.c

编译.

riscv64-unknown-linux-gnu-gcc hello.c -o hello

查看文件格式.

file hello
# hello: ELF 64-bit LSB pie executable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv64-lp64d.so.1, for GNU/Linux 4.15.0, with debug_info, not stripped

3.5 gcc stage2

目前的 GCC 是不够完整的: 它没有 C++ 标准库(libstdc++), 不支持线程, 也不支持共享库.

我们删除之前编译的版本.

cd $SOURCES/gcc-14.2.0
rm -rf build
mkdir build
cd build

这次配置增加了共享库, 线程, c++.

../configure                                       \
    --target=riscv64-unknown-linux-gnu             \
    --prefix=$LFS/tools                            \
    --with-glibc-version=2.40                      \
    --with-sysroot=$LFS                            \
    --enable-default-pie                           \
    --enable-default-ssp                           \
    --disable-nls                                  \
    --disable-multilib                             \
    --disable-libvtv                               \
    --enable-languages=c,c++                       \
    --enable-shared                                \
    --enable-threads=posix                         \
    --enable-libstdcxx                             \
    --enable-libatomic                             \
    --enable-libgomp                               \
    --enable-libquadmath                           \
    --enable-libssp                                \
    --enable-libitm
make -j$(nproc)
make install

验证.

cat <<'EOF' > hello.cpp
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3};
    for (auto i : v) {
        std::cout << "Value: " << i << std::endl;
    }
    return 0;
}
EOF

编译.

riscv64-unknown-linux-gnu-g++ hello.cpp -o hello_Cpp
file hello_Cpp

3.6 bash

现在不安装 bash 就进入 chroot 环境会黑屏一片.

cp -ar bash-5.2.32.tar.gz $LFS/sources/
cd $LFS/sources
tar -xf bash-5.2.32.tar.gz
cd bash-5.2.32/
./configure --prefix=/usr                      \
            --host=riscv64-unknown-linux-gnu   \
            --without-bash-malloc              \
            CFLAGS="-g -O2 -Wno-implicit-function-declaration"
make -j$(nproc)
make DESTDIR=$LFS install

完成之后会生成目录.

ls -l $LFS/usr/bash

3.7 coreutils

一个系统需要有最基础的 ls, cp, mv, mkdir 这些命令.

cp -ar coreutils-9.5* $SOURCES
cd $LFS/sources
tar -xf coreutils-9.5.tar.xz
cd coreutils-9.5/
patch -Np1 -i ../coreutils-9.5-i18n-2.patch
./configure --prefix=/usr                     \
            --host=riscv64-unknown-linux-gnu  \
            --enable-install-program=hostname \
            --enable-no-install-program=kill,uptime \
            FORCE_UNSAFE_CONFIGURE=1
make -j$(nproc)
make DESTDIR=$LFS install

验证.

ls -l $LFS/usr/bin/ls
ls -l $LFS/usr/bin/mkdir
ls -l $LFS/usr/bin/cp

3.8 安装 fastfetch

为了让进入系统的时候能够打印出系统的信息, 我们需要这个工具.

cd $SOURCES
git clone https://github.com/fastfetch-cli/fastfetch.git
cd fastfetch

交叉编译.

mkdir build && cd build
cmake .. \
  -DCMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc \
  -DCMAKE_CXX_COMPILER=riscv64-unknown-linux-gnu-g++ \
  -DCMAKE_INSTALL_PREFIX=/usr \
  -DENABLE_EGL=OFF \
  -DENABLE_GLX=OFF \
  -DENABLE_X11=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_XEXT=OFF \
  -DENABLE_WAYLAND=OFF \
  -DENABLE_VULKAN=OFF -DENABLE_OPENCL=OFF -DENABLE_DRM=OFF \
  -DENABLE_GIO=OFF -DENABLE_DBUS=OFF -DENABLE_PULSE=OFF \
  -DENABLE_ZLIB=OFF -DENABLE_SQLITE3=OFF -DENABLE_IMAGEMAGICK=OFF -DENABLE_XFCONF=OFF \
  -DCMAKE_DISABLE_FIND_PACKAGE_X11=ON \
  -DCMAKE_DISABLE_FIND_PACKAGE_OpenGL=ON \
  -DCMAKE_DISABLE_FIND_PACKAGE_OpenCL=ON \
  -DCMAKE_DISABLE_FIND_PACKAGE_Wayland=ON
make -j$(nproc)
sudo make DESTDIR=$LFS install

到目前为止, 已经可以直接去 4 了, 但是要是想在真机或者虚拟机运行的话, 还是得继续完成 3.9.

3.9 安装 sysvinit

当内核完成硬件初始化之后, 会启动第一个 init 进程.

sysvinit 和 systemd 就是传统和现代方式的两种 init 系统.

我们选择前者, 因为它的依赖不多.

cp -ar sysvinit-3.10* $LFS/sources/
cd $LFS/sources
tar -xf sysvinit-3.10.tar.xz
cd sysvinit-3.10/
patch -Np1 -i ../sysvinit-3.10-consolidated-1.patch
make CC=riscv64-unknown-linux-gnu-gcc
sudo make ROOT=$LFS install

此时我们可以看到 $LFS/sbin/ 目录下已经生成了 init, halt, shutdown 等核心程序

3.10 安装 utils-linux

该软件包包含 mount, umount, getty 这些基础的指令. 如果不编译的话很难成功进入安装了 sysvinit 的系统.

cp -ar util-linux-2.40.2.tar.xz $LFS/sources/
cd $LFS/sources
tar -xf util-linux-2.40.2.tar.xz
cd util-linux-2.40.2/
./configure --host=riscv64-unknown-linux-gnu \
            --build=$(build-aux/config.guess) \
            --libdir=/usr/lib    \
            --runstatedir=/run   \
            --disable-chfn-chsh  \
            --disable-login      \
            --disable-nologin    \
            --disable-su         \
            --disable-setpriv    \
            --disable-runuser    \
            --disable-pylibmount \
            --disable-static     \
            --disable-liblastlog2 \
            --without-python     \
            --without-tinfo      \
            --without-ncurses    \
            --without-readline   \
            ADJTIME_PATH=/var/lib/hwclock/adjtime
make -j$(nproc)
sudo env PATH="$PATH" LFS="$LFS" make DESTDIR="$LFS" install

这里可能会报错.

我们看看自己需要的软件在不在就可以了.

ls -l $LFS/bin/mount
ls -l $LFS/sbin/agetty
ls -l $LFS/usr/lib/libmount.so.1
chgrp tty /mnt/lfs/usr/bin/wall
chgrp: changing group of '/mnt/lfs/usr/bin/wall': Operation not permitted
make[4]: *** [Makefile:18850: install-exec-hook-wall] Error 1
make[4]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2'
make[3]: *** [Makefile:18004: install-exec-am] Error 2
make[3]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2'
make[2]: *** [Makefile:17269: install-am] Error 2
make[2]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2'
make[1]: *** [Makefile:16951: install-recursive] Error 1
make[1]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2'
make: *** [Makefile:17262: install] Error 2

我们不用理会, 因为必要的软件其实已经成功安装了.

4 进入 chroot 环境

创建基本的目录.

sudo mkdir -pv $LFS/{dev,proc,sys,run,etc,var,tmp}
sudo mkdir -pv $LFS/usr/{bin,sbin,lib}

挂载文件系统.

sudo mount -v --bind /dev $LFS/dev
sudo mount -v --bind /dev/pts $LFS/dev/pts
sudo mount -v -t proc proc $LFS/proc
sudo mount -v -t sysfs sysfs $LFS/sys
sudo mount -v -t tmpfs tmpfs $LFS/run

创建必要的链接.

# 为什么创建这些链接, 因为我 chroot 的时候发现抱错了, 一个个试的.
sudo ln -sf bash $LFS/bin/sh
sudo ln -sv /usr/lib/ld-linux-riscv64-lp64d.so.1 $LFS/lib/ld-linux-riscv64-lp64d.so.1
sudo ln -sv usr/bin bin
sudo ln -sv usr/sbin sbin
sudo ln -sv usr/lib lib

正式进入 chroot

sudo chroot "$LFS" /usr/bin/env -i   \
    HOME=/root                  \
    TERM="$TERM"                \
    PS1='(ruyi chroot):'        \
    PATH=/usr/bin:/usr/sbin     \
    /bin/bash --login

我们来看看 fastfetch 结果.

alt text

卸载挂载的文件系统方法如下.

sudo umount -v $LFS/run
sudo umount -v $LFS/sys
sudo umount -v $LFS/proc
sudo umount -v $LFS/dev/pts
sudo umount -v $LFS/dev

5 在虚拟机运行 LFS 的系统

chroot 不需要内核, 因为它借用宿主机的, 但虚拟机需要.

当然! 如果想在虚拟机跑也是 ok 滴!

5.1 编译内核

# 我们只需要一个内核就够了
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc) Image

5.2 完善系统

首先我们在进入系统之前需要先让内核能识别到硬盘.

cat > $LFS/etc/fstab << "EOF"
/dev/vda2      /            ext4    defaults            1     1
EOF

如果希望系统进入之后就能够看见到 fastfetch.

echo "/usr/bin/fastfetch" >> $LFS/etc/profile

创建 inittab 文件.

sudo bash -c "cat > $LFS/etc/inittab << 'EOF'
id:3:initdefault:
# 系统启动的第一格脚本.
si::sysinit:/etc/rc.d/init.d/rc S

# ID 不能太长, 亲测试会报错.
# 如果不需要用户则执行下面这一行替换最下面的一行
# 目前用户登陆还没有更新, 后续有时间我登陆, 原因是需要安装 login
# login 必须要在 chroot 之后安装, 还要安装一些其他包, 比较麻烦
# s0:2345:respawn:/bin/sh
s0:2345:respawn:/sbin/agetty 115200 ttyS0 vt100
EOF"

sudo ln -sf agetty $LFS/sbin/getty

然后编辑我们的启动脚本.

这里我选择加入了 logo.txt.

这里如果不想加入自己的 logo, 可以跳过这一步骤.

sudo bash -c "printf '
\033[1;36m      _         _       
\033[1;36m     (_)_   __ | | ___  
\033[1;32m     | \ \ / / | |/ _ \ 
\033[1;32m     | |\ V /  | |  __/ 
\033[1;33m    _/ | \_/   |_|\___| 
\033[1;33m   |__/                 
\033[1;34m   --- RISC-V LFS --- \033[0m
' > $LFS/usr/share/jvle_logo.txt"

继续.

# 创建目录
sudo mkdir -pv $LFS/etc/rc.d/init.d

# 写入脚本内容
sudo bash -c "cat > $LFS/etc/rc.d/init.d/rc << 'EOF'
#!/bin/sh
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LD_LIBRARY_PATH=/lib:/usr/lib

mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
mount -t tmpfs tmpfs /run

echo -e '\033[1;32mBooting jvle Custom System...\033[0m'

# 这里我添加了自己的 logo
/usr/bin/fastfetch --file /usr/share/logo.txt --logo-color-1 32

echo 'jvle-RISCV' > /proc/sys/kernel/hostname
PS1='[jvle@riscv \W]# '
EOF"

sudo chmod +x $LFS/etc/rc.d/init.d/rc

加入 login 功能.

TODO.

5.3 创建系统镜像

然后创建系统镜像.

mkdir -pb $LFS/boot
cd $LFS/boot
dd if=/dev/zero of=riscv_lfs.img bs=1M count=20480 # 20GB
mkfs.ext4 riscv_lfs.img
mkdir -p /mnt/lfs_disk
sudo mount riscv_lfs.img /mnt/lfs_disk
sudo cp -a $LFS/* /mnt/lfs_disk/
sudo umount /mnt/lfs_disk

5.4 启动系统

qemu-system-riscv64 -nographic -machine virt \
    -kernel $LFS/linux-6.18.5/arch/riscv/boot/Image \
    -append "root=/dev/vda rw console=ttyS0" \
    -drive file=$LFS/boot/riscv_lfs.img,format=raw,id=hd0 \
    -device virtio-blk-device,drive=hd0

alt text

6 快速启动成品

成品链接: https://github.com/Jvlegod/lfs-from-riscv 成品校验: 点击下载压缩包

下载我给出的 rootfs.

根据 5.3 的方法操作, 然后根据 5.4 直接启动.

7 可选功能包

7.1 kmod

这会加入 insmod, rmmod 这些模块的功能.

tar -xf kmod-33.tar.xz
cd kmod-33
./configure --host=riscv64-unknown-linux-gnu \
            --prefix=/usr \
            --bindir=/bin \
            --sysconfdir=/etc \
            --with-zlib=no \
            --with-xz=no \
            --with-zstd=no \
            --with-openssl=no \
            --disable-manpages
make -j$(nproc)
sudo make DESTDIR=${LFS} install