sysmaster 移植到 openEuler RISC-V

sysmaster 移植到 openEuler RISC-V

0 Intro

sysmasteropenEuler 创新的、用 Rust 重新设计的1号进程,适用从云到端的各种应用场景。

本文尝试在 openEuler RISC-V 23.09 上移植并运行 sysmaster

参考:laokz: 在RISC-V虚拟机上体验OE创新的1号进程sysMaster

1. 准备 openEuler RISC-V 23.09 环境

  • 官网安装指导文档中详细介绍了如何使用 qemu 运行 openEuler RISC-V 23.09 虚拟机。需要注意的是,该文档中提供的镜像链接中的镜像,不支持全量软件源,下载镜像时可以从此处下载对应文件作为替换。

  • 安装一下构建 sysmaster 需要的依赖:

sudo dnf install git python3-pre-commit
  • 下载源代码
git clone https://github.com/jmesmon/ioctl/
git clone https://gitee.com/openeuler/sysmaster.git
2 Likes

2. 打补丁以支持 RISC-V

已经修改好的源代码可以直接从wangyaoyong/my_sysmasterwangyaoyong/my_ioctl下载。

详细的修改如下。

  1. 修改 ioctl/ioctls/Cargo.toml 文件中的 ioctl-sys 的版本限定:
[dependencies]
libc = "0.2"
- ioctl-sys = { path = "../ioctl-sys", version = ">=0.6, <0.8" }
+ ioctl-sys = { path = "../ioctl-sys", version = ">=0.6, <=0.8" }

就是加了个等号,因为 ioctl-sys 0.8.0 版本支持了 RISC-V

  1. 修改 sysmaster/Cargo.lock 文件
dependencies = [
  "hwdb",
  "input-event-codes",
  "input_event_codes_rs",
- "ioctl-sys",
+ "ioctl-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ioctls",
  "kmod_rs",
  "lazy_static",

加上了版本限定。

1 Like
+[[package]]
+name = "ioctl-sys"
-version = "0.7.1"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9d0b6b23885487578d10590edc36fd95426257c7017973b20633e34df23b08"
+checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
 
 [[package]]
 name = "ioctls"
 version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5780ca662f733ea1b940647b657d5324abc55a7d8d9b0628e8af8fe96ab3ed2"
 dependencies = [
- "ioctl-sys",
+ "ioctl-sys 0.8.0",
  "libc",
 ]

对应修改版本信息。

  1. 修改 sysmaster/Cargo.toml
 [patch.crates-io.loopdev]
 git = 'https://gitee.com/overweight/loopdev'
 branch = 'bump-bindgen-reduce-version'
+
+[patch.crates-io]
+ioctls = { path = "/path/to/ioctl/ioctls" }

注意这里的 ioctl 路径替换成上面克隆的路径。

  1. 修改 sysmaster/exts/devmaster/Cargo.toml
confique = { version = "0.1.3", default-features = false, features = ['toml'] }
 futures = { version = "0.3.13", default-features = false }
 input-event-codes = "5.16.8"
-ioctl-sys = "0.7.1"
+ioctl-sys = "0.8.0"
 ioctls = "0.6.1"
 lazy_static = "1.4.0"
 libc = { version = "0.2.*", default-features = false }
  1. 修改 sysmaster/exts/switch_root/src/switch_root.rs
macro_rules! LIB_ARCH_TUPLE {
    () => {
        if cfg!(target_arch = "x86_64") {
            BaseFilesystem::new(
                "lib64",
                MODE755,
                vec!["usr/sbin/x86_64-linux-gnu", "usr/lib64"],
                "ld-linux-x86-64.so.2",
                false,
            )
        } else if cfg!(target_arch = "aarch64") {
            BaseFilesystem::new(
                "lib64",
                MODE777,
                vec!["usr/sbin/x86_64-linux-gnu", "usr/lib64"],
                "ld-linux-aarch64.so.1",
                false,
            )
+        } else if cfg!(target_arch = "riscv64") {
+            BaseFilesystem::new(
+                "lib64",
+                MODE777,
+                vec!["usr/sbin/riscv64-linux-gnu", "usr/lib64/lp64d"],
+                "ld-linux-riscv64-lp64d.so.1",
+                false,
+            )
        } else {
            BaseFilesystem::new(
                "lib64",
                MODE777,
                vec!["usr/sbin/x86_64-linux-gnu", "usr/lib64"],
                "ld-linux-aarch64.so.1",
                false,
            )
        }
    };
}

添加一个 riscv64 的分支。

1 Like
  1. 修改 sysmaster/libs/basic/src/machine.rs
   	/// detect virtual machine
    pub fn detect_vm() -> Self {
        static mut CACHED_FOUND: Machine = Machine::None;
        unsafe {
            if CACHED_FOUND != Machine::None {
                return CACHED_FOUND;
            }
        }

        let vm_dmi = Machine::detect_vm_dmi();
        if vm_dmi == Machine::Oracle || vm_dmi == Machine::Xen {
            unsafe_set_and_return!(CACHED_FOUND, vm_dmi);
        }

        let vm_uml = Machine::detect_vm_uml();
        unsafe_set_and_return!(CACHED_FOUND, vm_uml);

        // let vm_hyper = Machine::detect_vm_cpuid(); unsupported!!
        // unsafe_set_and_return!(CACHED_FOUND, vm_hyper);

        let vm_xen = Machine::detect_vm_xen();
        unsafe_set_and_return!(CACHED_FOUND, vm_xen);

        let vm_hyper = Machine::detect_vm_hypervisor();
        unsafe_set_and_return!(CACHED_FOUND, vm_hyper);

        #[cfg(target_arch = "aarch64")]
        let vm = Machine::detect_vm_device_tree();
        #[cfg(target_arch = "aarch64")]
        unsafe_set_and_return!(CACHED_FOUND, vm);

+        #[cfg(target_arch = "riscv64")]
+        let vm = Machine::detect_vm_device_tree();
+        #[cfg(target_arch = "riscv64")]
+        unsafe_set_and_return!(CACHED_FOUND, vm);

        unsafe { CACHED_FOUND }
    }
	#[cfg(target_arch = "aarch64")]
    /// detect vm by device tree
    pub fn detect_vm_device_tree() -> Self {
        if let Ok(v) = fs::read_to_string("/proc/device-tree/hypervisor/compatible") {
            return Machine::from(v.as_str());
        };

        if Path::new("/proc/device-tree/ibm,partition-name").exists()
            && Path::new("/proc/device-tree/hmc-managed?").exists()
            && Path::new("/proc/device-tree/chosen/qemu,graphic-width").exists()
        {
            return Machine::PowerRVM;
        }
        if let Ok(dir) = std::fs::read_dir("/proc/device-tree") {
            for entry in dir.flatten() {
                if entry.path().to_string_lossy().contains("fw-cfg") {
                    return Machine::Qemu;
                }
            }
        }
        Machine::None
    }

+    #[cfg(target_arch = "riscv64")]
+    /// detect vm by device tree
+    pub fn detect_vm_device_tree() -> Self {
+        if let Ok(dir) = std::fs::read_dir("/proc/device-tree") {
+            for entry in dir.flatten() {
+                if entry.path().to_string_lossy().contains("fw-cfg") {
+                    return Machine::Qemu;
+                }
+            }
+        }
+        Machine::None
+    }

    /// detect vm for uml
    pub fn detect_vm_uml() -> Self {
        let cpuinfo_path = PathBuf::from("/proc/cpuinfo");
        if cpuinfo_path.exists() {
            if let Ok(inner) = File::open(cpuinfo_path) {
                for line in BufReader::new(inner).lines().flatten() {
                    if line.starts_with("vendor_id") && line.contains("User Mode Linux") {
                        return Machine::Uml;
                    }
                }
            }
        }
        Machine::None
    }
1 Like
  1. 修改 sysmaster/libs/basic/src/uuid.rs
#[cfg(target_arch = "aarch64")]
/// GPT_ROOT_NATIVE UUID type
pub const GPT_ROOT_NATIVE: Uuid = Uuid([
    0xb9, 0x21, 0xb0, 0x45, 0x1d, 0xf0, 0x41, 0xc3, 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae,
]);
#[cfg(target_arch = "x86_64")]
/// GPT_ROOT_NATIVE UUID type
pub const GPT_ROOT_NATIVE: Uuid = Uuid([
    0x69, 0xda, 0xd7, 0x10, 0x2c, 0xe4, 0x4e, 0x3c, 0xb1, 0x6c, 0x21, 0xa1, 0xd4, 0x9a, 0xbe, 0xd3,
]);
+#[cfg(target_arch = "riscv64")]
+/// GPT_ROOT_NATIVE UUID type
+pub const GPT_ROOT_NATIVE: Uuid = Uuid([
+    0x72, 0xec, 0x70, 0xa6, 0xcf, 0x74, 0x40, 0xe6, 0xbd, 0x49, 0x4b, 0xda, 0x08, 0xe8, 0xf2, 0x24,
+]);
1 Like

3. 构建 sysmaster

cd sysmaster
sh build.sh

期间会自动下载 rust 1.57 及其 crates 包,若失败则多次运行直到全部下载完毕。或者直接手动下载这些包:

git fetch --force --update-head-ok https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index+HEAD:refs/remotes/origin/HEAD
  • 运行 sh build.sh 构建脚本时,要么一直使用普通用户权限,要么直接切换到 root 用户执行。
    • 不然的话,假设第一次以普通权限构建失败,后面如果尝试 sudo 的话,会发现识别不到 cargo 等命令,因为初次安装时会把 cargo 路径添加到当时用户的路径中。
  • 构建耗时较长,qemu 构建大概需要两个小时。因此我尝试了在荔枝派4A上安装 openEuler RISC-V 23.09 进行构建,之后发现构建出来的 target 可以直接拷贝到 qemu 虚拟机中安装,在实机中构建时间小于一小时。

4. 安装 sysmaster

sudo sh docs/use/虚机中替代pid1运行/install_sysmaster.sh
  • 注意要在 sysmaster/ 下执行,疑似有的命令写的是相对路径,如果不在项目根目录的话,会找不到构建出的 target 目录。
  • 中文路径

5. 以 sysmaster 作为1号进程启动

  • 目前只有虚拟机启动的脚本,因此没有在荔枝派4A上尝试成功。

制作不需要 systemd 的启动镜像:

sudo dracut -f --omit "systemd systemd-initrd systemd-networkd dracut-systemd" /boot/initrd_withoutsd.img

之后在 /boot/ 中的 initrd_withoutsd.imgvmlinuz-6.4.0... 文件拷贝到宿主机(qemu 和宿主机拷贝文件可以参考Qemu虚拟机与宿主机之间文件传输)。

拷贝到宿主机后,vmlinuz-6.4.0... 文件其实是压缩包,需要先改为 .gz 后缀,再gzip -d *.gz 解压后使用。

然后修改之前下载镜像时的 start.sh 脚本中的 qemu 启动参数,修改为如下所示:

qemu-system-riscv64 \
  -nographic -machine virt \
  -smp 4 -m 4G \
  -kernel vmlinuz-6.4.0-10.1.0.20.oe2309.riscv64 \
  -initrd initrd_withoutsd.img \
  -drive file=openEuler-23.09-RISC-V-qemu-riscv64.qcow2,format=qcow2,id=hd0 \
  -object rng-random,filename=/dev/urandom,id=rng0 \
  -device virtio-rng-device,rng=rng0 \
  -device virtio-blk-device,drive=hd0 \
  -device virtio-net-pci,netdev=usernet \
  -netdev user,id=usernet,hostfwd=tcp::12345-:22\
  -append 'root=/dev/vda2 rw init=/init console=ttyS0 selinux=0 highres=off earlycon'

主要更改是取消-bios,增加-kernel、-initrd、-append。

1 Like

执行脚本,从开机日志中可以看到 sysmaster 成功运行。