Selaa lähdekoodia

成功在riscv上启动efi并且能够输出 (#2)

* 成功在riscv上启动efi并且能够输出

* fmt

* update readme

* update github workflow
LoGin 5 kuukautta sitten
vanhempi
commit
0ec3a34a58

+ 1 - 1
.github/workflows/cache-toolchain.yml

@@ -27,7 +27,7 @@ jobs:
           name: Install toolchain
           continue-on-error: true
           run:  |
-            sudo sh -c "apt update && apt install -y llvm-dev libclang-dev clang gcc-multilib libssl-dev pkg-config"
+            sudo sh -c "apt update && apt install -y llvm-dev libclang-dev clang gcc-multilib libssl-dev pkg-config build-essential gcc-riscv64-unknown-elf"
             cargo install cargo-binutils
             rustup toolchain install nightly
             rustup default nightly

+ 2 - 0
.gitignore

@@ -17,3 +17,5 @@ Cargo.lock
 # Added by cargo
 
 /target
+
+/output

+ 3 - 0
.vscode/settings.json

@@ -1,4 +1,7 @@
 {
     "rust-analyzer.cargo.target": "riscv64imac-unknown-none-elf",
     "rust-analyzer.checkOnSave.allTargets": false,
+    "rust-analyzer.linkedProjects": [
+        "./Cargo.toml"
+    ],
 }

+ 8 - 2
Cargo.toml

@@ -4,10 +4,16 @@ version = "0.1.0"
 edition = "2021"
 build = "build.rs"
 
+
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-
+log = "0.4.20"
+uefi = { version = "0.26.0", features = ["alloc"] }
+uefi-services = "0.23.0"
 
 [build-dependencies]
-cc = { version = "1.0.83", features = ["parallel"] }
+dragon_boot_build = { path = "build-scripts/dragon_boot_build" }
+
+[workspace]
+exclude = [ "build-scripts" ]

+ 40 - 2
Makefile

@@ -1,4 +1,4 @@
-.PHONY: all clean
+.PHONY: all clean fmt clippy qemu run
 
 # 检查是否需要进行fmt --check
 # 解析命令行参数  
@@ -12,7 +12,33 @@ endif
 
 export ARCH ?= riscv64
 
+ifeq ($(ARCH), riscv64)
+	RUST_TARGET=riscv64imac-unknown-none-elf
+else
+	@echo "ARCH=$(ARCH) is not supported"
+	@exit 1
+endif
+
+EFI_OUTPUT_DIR?=output
+
+OBJCOPY_FLAGS=
+
+# OBJCOPY_FLAGS+=-j .header -j .text -j .plt -j .sdata -j .data -j .dynamic -j .dynstr -j .dynsym -j .rel -j .rel.*  -j .rela* -j .reloc -j .reloc* -j .sbss
+
+
+OBJCOPY_FLAGS+= --output-target=binary
+
+export RUSTFLAGS=-Crelocation-model=pic
+
+ifeq ($(ARCH), riscv64)
+	OBJCOPY_FLAGS+= --binary-architecture=riscv
+else
+	@echo "ARCH=$(ARCH) is not supported"
+	@exit 1
+endif
+
 all:
+	@mkdir -p $(EFI_OUTPUT_DIR)
 ifeq ($(ARCH), riscv64)
 	$(MAKE) riscv64imac
 else
@@ -21,7 +47,12 @@ else
 endif
 
 riscv64imac:
-	@cargo build --release --target riscv64imac-unknown-none-elf
+	RUSTFLAGS=$(RUSTFLAGS) cargo build --release --target riscv64imac-unknown-none-elf
+	rust-objcopy $(OBJCOPY_FLAGS) target/$(RUST_TARGET)/release/dragon_boot $(EFI_OUTPUT_DIR)/dragon_boot-riscv64imac.efi
+
+run:
+	@$(MAKE) all || exit 1
+	@$(MAKE) qemu
 
 clean:
 	@cargo clean
@@ -29,3 +60,10 @@ clean:
 
 fmt:
 	@cargo fmt --all $(FMT_CHECK)
+
+clippy:
+	@cargo clippy --all --target $(RUST_TARGET) --all-features
+
+
+qemu:
+	cd tools && ./run-qemu.sh && cd ..

+ 1 - 1
README.md

@@ -6,7 +6,7 @@ A stage2 UEFI bootloader of DragonOS in pure Rust.
 
 ## 功能
 
-- [ ] 从UEFI启动DragonBoot
+- [x] 从UEFI启动DragonBoot
 - [ ] 显示启动菜单
 - [ ] 从磁盘启动DragonOS
 - [ ] 启动配置

+ 4 - 0
build-scripts/Cargo.toml

@@ -0,0 +1,4 @@
+[workspace]
+members = [
+    "dragon_boot_build",
+]

+ 10 - 0
build-scripts/dragon_boot_build/Cargo.toml

@@ -0,0 +1,10 @@
+[package]
+name = "dragon_boot_build"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+lazy_static = "1.4.0"
+cc = { version = "1.0.83", features = ["parallel"] }

+ 28 - 0
build-scripts/dragon_boot_build/src/cfiles/arch/mod.rs

@@ -0,0 +1,28 @@
+use std::path::PathBuf;
+
+use cc::Build;
+
+use crate::utils::cargo_handler::{CargoHandler, TargetArch};
+
+pub mod riscv64;
+
+pub(super) trait CFilesArch {
+    /// 设置架构相关的宏定义
+    fn setup_defines(&self, c: &mut Build);
+    /// 设置架构相关的全局包含目录
+    fn setup_global_include_dir(&self, c: &mut Build);
+    /// 设置需要编译的架构相关的文件
+    fn setup_files(&self, c: &mut Build, files: &mut Vec<PathBuf>);
+
+    /// 设置架构相关的全局编译标志
+    fn setup_global_flags(&self, c: &mut Build);
+}
+
+/// 获取当前的架构;
+pub(super) fn current_cfiles_arch() -> &'static dyn CFilesArch {
+    let arch = CargoHandler::target_arch();
+    match arch {
+        TargetArch::Riscv64 => &riscv64::RiscV64CFilesArch,
+        _ => panic!("Unsupported arch: {:?}", arch),
+    }
+}

+ 38 - 0
build-scripts/dragon_boot_build/src/cfiles/arch/riscv64.rs

@@ -0,0 +1,38 @@
+use std::path::PathBuf;
+
+use crate::{constant::ARCH_DIR_RISCV64, utils::FileUtils};
+
+use super::CFilesArch;
+
+pub(super) struct RiscV64CFilesArch;
+
+impl CFilesArch for RiscV64CFilesArch {
+    fn setup_defines(&self, c: &mut cc::Build) {
+        c.define("__riscv64__", None);
+        c.define("__riscv", None);
+    }
+
+    fn setup_global_include_dir(&self, _c: &mut cc::Build) {}
+
+    fn setup_files(&self, _c: &mut cc::Build, files: &mut Vec<std::path::PathBuf>) {
+        files.append(&mut FileUtils::list_all_files(
+            &arch_path(""),
+            Some("S"),
+            true,
+        ));
+    }
+
+    fn setup_global_flags(&self, c: &mut cc::Build) {
+        // 在这里设置编译器,不然的话vscode的rust-analyzer会报错
+        c.compiler("riscv64-unknown-elf-gcc");
+        // // c.flag("-march=rv64imafdc");
+        // c.no_default_flags(true);
+        c.flag("-mcmodel=medany");
+        c.flag("-mabi=lp64");
+        c.flag("-march=rv64imac");
+    }
+}
+
+fn arch_path(relative_path: &str) -> PathBuf {
+    PathBuf::from(format!("{}/{}", ARCH_DIR_RISCV64, relative_path))
+}

+ 71 - 0
build-scripts/dragon_boot_build/src/cfiles/mod.rs

@@ -0,0 +1,71 @@
+use std::path::PathBuf;
+
+use cc::Build;
+
+use crate::utils::cargo_handler::CargoHandler;
+
+use self::arch::current_cfiles_arch;
+
+mod arch;
+
+/// 构建项目的c文件
+pub struct CFilesBuilder;
+
+impl CFilesBuilder {
+    pub fn build() {
+        let mut c = cc::Build::new();
+
+        Self::setup_global_flags(&mut c);
+        Self::setup_defines(&mut c);
+        Self::setup_global_include_dir(&mut c);
+        Self::setup_files(&mut c);
+        c.compile("dragon_boot_cfiles");
+    }
+
+    fn setup_global_flags(c: &mut Build) {
+        c.flag("-fno-builtin")
+            .flag("-nostdlib")
+            .flag("-fno-stack-protector")
+            .flag("-fno-pie")
+            .flag("-Wno-expansion-to-defined")
+            .flag("-Wno-unused-parameter")
+            .flag("-O1")
+            .flag("-fPIC");
+
+        // set Arch-specific flags
+        current_cfiles_arch().setup_global_flags(c);
+    }
+
+    fn setup_defines(c: &mut Build) {
+        if let Ok(k) = std::env::var("EMULATOR") {
+            c.define("EMULATOR", Some(k.as_str()));
+        } else {
+            c.define("EMULATOR", "__NO_EMULATION__");
+        }
+
+        current_cfiles_arch().setup_defines(c);
+    }
+
+    fn setup_global_include_dir(c: &mut Build) {
+        c.include("src/include");
+        c.include("src");
+        c.include(".");
+
+        current_cfiles_arch().setup_global_include_dir(c);
+    }
+
+    /// 设置需要编译的文件
+    fn setup_files(c: &mut Build) {
+        let mut files: Vec<PathBuf> = Vec::new();
+
+        current_cfiles_arch().setup_files(c, &mut files);
+
+        Self::set_rerun_if_files_changed(&files);
+        c.files(files.as_slice());
+    }
+
+    /// 设置Cargo对文件更改的监听
+    fn set_rerun_if_files_changed(files: &Vec<PathBuf>) {
+        CargoHandler::emit_rerun_if_files_changed(files.as_slice());
+    }
+}

+ 1 - 0
build-scripts/dragon_boot_build/src/constant/mod.rs

@@ -0,0 +1 @@
+pub const ARCH_DIR_RISCV64: &str = "src/arch/riscv64";

+ 16 - 0
build-scripts/dragon_boot_build/src/lib.rs

@@ -0,0 +1,16 @@
+#[macro_use]
+extern crate lazy_static;
+extern crate cc;
+
+mod cfiles;
+mod constant;
+mod utils;
+
+/// 运行构建
+pub fn run() {
+    println!("cargo:rustc-link-search=src");
+
+    crate::cfiles::CFilesBuilder::build();
+    // 设置链接参数
+    crate::utils::ld_scripts::setup();
+}

+ 83 - 0
build-scripts/dragon_boot_build/src/utils/cargo_handler.rs

@@ -0,0 +1,83 @@
+use std::{env, path::PathBuf};
+
+lazy_static! {
+    static ref CARGO_HANDLER_DATA: CargoHandlerData = CargoHandlerData::new();
+}
+
+struct CargoHandlerData {
+    target_arch: TargetArch,
+}
+
+impl CargoHandlerData {
+    fn new() -> Self {
+        CargoHandlerData {
+            target_arch: TargetArch::new(),
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct CargoHandler;
+
+impl CargoHandler {
+    pub fn readenv(key: &str) -> Option<String> {
+        if let Ok(value) = env::var(key) {
+            Some(value)
+        } else {
+            None
+        }
+    }
+
+    /// 获取当前编译的目标架构
+    pub fn target_arch() -> TargetArch {
+        CARGO_HANDLER_DATA.target_arch
+    }
+
+    /// 设置Cargo对文件更改的监听
+    ///
+    /// ## Parameters
+    ///
+    /// - `files` - The files to set rerun build
+    pub fn emit_rerun_if_files_changed(files: &[PathBuf]) {
+        for f in files {
+            println!("cargo:rerun-if-changed={}", f.to_str().unwrap());
+        }
+    }
+
+    /// 设置链接参数
+    pub fn emit_link_arg(arg: &str) {
+        println!("cargo:rustc-link-arg={}", arg);
+    }
+}
+
+/// 目标架构
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum TargetArch {
+    X86_64,
+    Aarch64,
+    Riscv64,
+    Mips64,
+    Powerpc64,
+    S390x,
+    Sparc64,
+    Unknown,
+}
+
+impl TargetArch {
+    pub fn new() -> Self {
+        let data = CargoHandler::readenv("CARGO_CFG_TARGET_ARCH")
+            .expect("CARGO_CFG_TARGET_ARCH is not set")
+            .to_ascii_lowercase();
+
+        match data.as_str() {
+            "x86_64" => TargetArch::X86_64,
+            "aarch64" => TargetArch::Aarch64,
+            "riscv64" => TargetArch::Riscv64,
+            "mips64" => TargetArch::Mips64,
+            "powerpc64" => TargetArch::Powerpc64,
+            "s390x" => TargetArch::S390x,
+            "sparc64" => TargetArch::Sparc64,
+            _ => TargetArch::Unknown,
+        }
+    }
+}

+ 16 - 0
build-scripts/dragon_boot_build/src/utils/ld_scripts.rs

@@ -0,0 +1,16 @@
+use super::cargo_handler::{CargoHandler, TargetArch};
+
+pub fn setup() {
+    let arch = CargoHandler::target_arch();
+    match arch {
+        TargetArch::Riscv64 => {
+            // CargoHandler::emit_link_arg("-Tsrc/arch/riscv64/link.ld");
+            CargoHandler::emit_link_arg("-Tsrc/arch/riscv64/link.ld");
+            CargoHandler::emit_link_arg("--emit-relocs");
+            CargoHandler::emit_link_arg("--nmagic");
+
+            CargoHandler::emit_link_arg("--no-relax");
+        }
+        _ => panic!("Unsupported arch: {:?}", arch),
+    }
+}

+ 50 - 0
build-scripts/dragon_boot_build/src/utils/mod.rs

@@ -0,0 +1,50 @@
+use std::path::PathBuf;
+
+pub mod cargo_handler;
+pub mod ld_scripts;
+
+pub struct FileUtils;
+
+impl FileUtils {
+    /// 列出指定目录下的所有文件
+    ///
+    /// ## 参数
+    ///
+    /// - `path` - 指定的目录
+    /// - `ext_name` - 文件的扩展名,如果为None,则列出所有文件
+    /// - `recursive` - 是否递归列出所有文件
+    pub fn list_all_files(path: &PathBuf, ext_name: Option<&str>, recursive: bool) -> Vec<PathBuf> {
+        let mut queue: Vec<PathBuf> = Vec::new();
+        let mut result = Vec::new();
+        queue.push(path.clone());
+
+        while !queue.is_empty() {
+            let path = queue.pop().unwrap();
+            let d = std::fs::read_dir(path);
+            if d.is_err() {
+                continue;
+            }
+            let d = d.unwrap();
+
+            d.for_each(|ent| {
+                if let Ok(ent) = ent {
+                    if let Ok(file_type) = ent.file_type() {
+                        if file_type.is_file() {
+                            if let Some(e) = ext_name {
+                                if let Some(ext) = ent.path().extension() {
+                                    if ext == e {
+                                        result.push(ent.path());
+                                    }
+                                }
+                            }
+                        } else if file_type.is_dir() && recursive {
+                            queue.push(ent.path());
+                        }
+                    }
+                }
+            });
+        }
+
+        return result;
+    }
+}

+ 3 - 1
build.rs

@@ -1 +1,3 @@
-fn main() {}
+fn main() {
+    dragon_boot_build::run();
+}

+ 5 - 5
src/arch/riscv64/crt0-efi-riscv64.S

@@ -152,15 +152,15 @@ _start:
 	sd			ra, 16(sp)
 
 	/* Run relocation */
-	lla			a0, ImageBase
-	lla			a1, _DYNAMIC
-	call		_relocate
-	bne			a0, zero, 0f
+	// lla			a0, ImageBase
+	// lla			a1, _DYNAMIC
+	// call		_relocate
+	// bne			a0, zero, 0f
 
 	/* Call EFI code */
 	ld			a1, 8(sp)
 	ld			a0, 0(sp)
-	call		efi_main
+	call	    efi_main
 
 	ld			ra, 16(sp)
 

+ 92 - 0
src/arch/riscv64/link.ld

@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * U-Boot riscv64 EFI linker script
+ *
+ * SPDX-License-Identifier:     BSD-2-Clause
+ *
+ * Modified from arch/arm/lib/elf_aarch64_efi.lds
+ */
+/**
+ * Sourced from
+ * https://source.denx.de/u-boot/u-boot/-/blob/52ba373b7825e9feab8357065155cf43dfe2f4ff/arch/riscv/lib/elf_riscv64_efi.lds
+ */
+
+OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+SECTIONS
+{
+        .text 0x0 : SUBALIGN(16) {
+                _text = .;
+                *(.text.head)
+                *(.text)
+                *(.text.*)
+                *(.gnu.linkonce.t.*)
+                *(.srodata)
+                *(.rodata*)
+                *(.got)
+                *(.got.*)
+                . = ALIGN(16);
+        }
+        
+        _etext = .;
+        . = ALIGN(16);
+        _text_size = . - _text;
+        .dynamic  : { *(.dynamic) }
+        .data : {
+                _data = .;
+                *(.sdata)
+                *(.sdata.*)
+                *(.data)
+                *(.data1)
+                *(.data.*)
+                *(.got.plt)
+                *(.got.plt.*)
+                
+
+                /*
+                 * The EFI loader doesn't seem to like a .bss section, so we
+                 * stick it all into .data:
+                 */
+                . = ALIGN(16);
+                _bss = .;
+                *(.sbss)
+                *(.scommon)
+                *(.dynbss)
+                *(.bss)
+                 
+                *(.bss.*)
+                *(COMMON)
+                . = ALIGN(16);
+                _bss_end = .;
+        }
+        
+        .rela (INFO) : {
+            *(.rela .rela*)
+        }
+
+        
+        /*
+         * Put _edata here so it all gets loaded by U-Boot.
+         * The script originally had this equal to _bss_end, but
+         * our .rela.dyn wasn't getting loaded into memory so we
+         * couldn't do any relocations.
+         *
+         * Here be dragons.  Do we need .dynsym/.dynstr too?
+         */
+        _edata = .;
+        _data_size = . - _etext;
+
+        . = ALIGN(4096);
+        .dynsym   : { *(.dynsym) }
+        . = ALIGN(4096);
+        .dynstr   : { *(.dynstr) }
+        . = ALIGN(4096);
+        .note.gnu.build-id : { *(.note.gnu.build-id) }
+        /DISCARD/ : {
+                
+                *(.eh_frame)
+                *(.note.GNU-stack)
+        }
+        .comment 0 : { *(.comment) }
+}

+ 87 - 0
src/lib.rs

@@ -1,2 +1,89 @@
 #![no_std]
 #![no_main]
+#![feature(fmt_internals)]
+
+use core::{
+    ffi::c_void,
+    fmt::{Formatter, Write},
+};
+extern crate alloc;
+
+use alloc::string::String;
+use log::info;
+use uefi::{
+    table::{Boot, SystemTable},
+    CStr16, Handle,
+};
+
+mod arch;
+
+extern "C" {
+    fn _start() -> !;
+}
+
+#[no_mangle]
+unsafe extern "efiapi" fn efi_main(
+    handle_ptr: *mut c_void,
+    system_table_ptr: *mut c_void,
+) -> usize {
+    rs_efi_main(handle_ptr, system_table_ptr)
+        .map(|_| uefi::Status::SUCCESS.0 as usize)
+        .unwrap_or_else(|e| e.0 as usize)
+}
+
+fn rs_efi_main(
+    handle_ptr: *mut c_void,
+    system_table_ptr: *mut c_void,
+) -> Result<(), uefi::prelude::Status> {
+    let image_handle =
+        unsafe { Handle::from_ptr(handle_ptr).ok_or(uefi::Status::INVALID_PARAMETER)? };
+    let mut system_table: SystemTable<uefi::table::Boot> =
+        unsafe { SystemTable::from_ptr(system_table_ptr).ok_or(uefi::Status::INVALID_PARAMETER)? };
+    unsafe { system_table.boot_services().set_image_handle(image_handle) };
+
+    uefi_services::init(&mut system_table).map_err(|e| e.status())?;
+
+    let mut buf = [0u16; 32];
+    system_table.stdout().write_str("123455\n");
+    let x = CStr16::from_str_with_buf("DragonBoot Starting...\n", &mut buf).unwrap();
+    system_table
+        .stdout()
+        .output_string(x)
+        .map_err(|e| e.status())?;
+
+    let x = String::from("AAAAAAAHello, world!\n");
+    system_table.stdout().write_str(x.as_str());
+
+    let args = core::format_args!("hgfhgfhfHello, world!\n");
+    // 这里println的FormatWriter里面的&'a dyn (Write +'a)貌似不能在重定位之前访问,不然的话会出现错误:
+    // ```
+    // Found EFI removable media binary efi/boot/bootriscv64.efi
+    // 20336 bytes read in 4 ms (4.8 MiB/s)
+    // Booting /efi\boot\bootriscv64.efi
+    // 123455
+    // DragonBoot Starting...
+    // AAAAAAAHello, world!
+    // Unhandled exception: Illegal instruction
+    // EPC: 00000000000012b0 RA: 000000009deee240 TVAL: 0000000000000000
+    // EPC: ffffffffe0abf2b0 RA: 000000007e9ac240 reloc adjusted
+    // Code: 0000 0000 0000 0000 0000 0000 0000 0000 (0000)
+    // UEFI image [0x000000009deec000:0x000000009def0f6f] '/efi\boot\bootriscv64.efi
+    // ```
+    //
+    // Fault的PC和值都是错误的,因此猜想动态分发这块的代码不是PIC的,需要重定位,因此不能在重定位之前用println
+
+    loop {}
+    // 执行下面这行会出错,就是上面注释说的那个错误
+    system_table.stdout().write_fmt(args);
+    // system_table.stdout().write_str(args);
+
+    loop {}
+    return Ok(());
+}
+
+#[no_mangle]
+fn _relocate() {
+    loop {}
+}
+
+pub fn x() {}

+ 3 - 15
src/main.rs

@@ -1,21 +1,9 @@
 #![no_std]
 #![no_main]
 
-mod arch;
+extern crate dragon_boot;
 
-#[no_mangle]
-fn efi_main() {
-    // println!("Hello, world!");
-    loop {}
-}
-
-#[no_mangle]
-fn _relocate() {
-    loop {}
-}
-
-#[panic_handler]
-fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
-    // println!("{}", info);
+fn main() {
+    dragon_boot::x();
     loop {}
 }

+ 4 - 0
tools/.gitignore

@@ -0,0 +1,4 @@
+*.tar.xz
+*.tar.gz
+
+/arch/riscv64/u-boot*

+ 169 - 0
tools/run-qemu.sh

@@ -0,0 +1,169 @@
+#!/bin/bash
+
+# uboot版本
+UBOOT_VERSION="v2023.10"
+RISCV64_UBOOT_PATH="arch/riscv64/u-boot-${UBOOT_VERSION}-riscv64"
+
+export ARCH=${ARCH:=riscv64}
+echo "ARCH: ${ARCH}"
+
+# 磁盘镜像
+DISK_NAME="disk-${ARCH}.img"
+
+QEMU=qemu-system-${ARCH}
+QEMU_MEMORY="512M"
+QEMU_SMP="2,cores=2,threads=1,sockets=1"
+QEMU_ACCELARATE=""
+QEMU_DISK_IMAGE="../output/${DISK_NAME}"
+QEMU_DRIVE="-drive id=disk,file=${QEMU_DISK_IMAGE},if=none"
+QEMU_DEVICES=" -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 "
+
+# 标准的trace events
+# qemu_trace_std=cpu_reset,guest_errors
+qemu_trace_std=cpu_reset
+
+QEMU_ARGUMENT=""
+
+if [ ${ARCH} == "riscv64" ]; then
+    QEMU_MACHINE=" -machine virt "
+    QEMU_MONITOR=""
+    QEMU_ARGUMENT+=" --nographic "
+
+else
+    echo "不支持的架构"
+    exit 1
+fi
+QEMU_ARGUMENT+=" -d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d ${QEMU_MONITOR} -d ${qemu_trace_std} "
+QEMU_ARGUMENT+=" -s ${QEMU_MACHINE} "
+QEMU_ARGUMENT+=" ${QEMU_DEVICES} ${QEMU_DRIVE} "
+
+
+TMP_LOOP_DEVICE=""
+
+# 安装riscv64的uboot
+install_riscv_uboot()
+{
+
+    if [ ! -d ${RISCV64_UBOOT_PATH} ]; then
+        echo "正在下载u-boot..."
+        uboot_tar_name="u-boot-${UBOOT_VERSION}-riscv64.tar.xz"
+        
+        uboot_parent_path=$(dirname ${RISCV64_UBOOT_PATH}) || (echo "获取riscv u-boot 版本 ${UBOOT_VERSION} 的父目录失败" && exit 1)
+
+        if [ ! -f ${uboot_tar_name} ]; then
+            wget https://mirrors.dragonos.org.cn/pub/third_party/u-boot/${uboot_tar_name} || (echo "下载riscv u-boot 版本 ${UBOOT_VERSION} 失败" && exit 1)
+        fi
+        echo "下载完成"
+        echo "正在解压u-boot到 '$uboot_parent_path'..."
+        mkdir -p $uboot_parent_path
+        tar xvf u-boot-${UBOOT_VERSION}-riscv64.tar.xz -C ${uboot_parent_path} || (echo "解压riscv u-boot 版本 ${UBOOT_VERSION} 失败" && exit 1)
+        echo "解压完成"
+        rm -rf u-boot-${UBOOT_VERSION}-riscv64.tar.xz
+    fi
+    echo "riscv u-boot 版本 ${UBOOT_VERSION} 已经安装"
+} 
+
+run_qemu()
+{
+    echo "正在启动qemu..."
+
+    if [ ${ARCH} == "riscv64" ]; then
+        QEMU_ARGUMENT+=" -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin "
+    fi
+
+    echo "qemu命令: ${QEMU} ${QEMU_ARGUMENT}"
+    ${QEMU} ${QEMU_ARGUMENT}
+}
+
+
+format_as_mbr() {
+    echo "Formatting as MBR..."
+   # 使用fdisk把disk.img的分区表设置为MBR格式(下方的空行请勿删除)
+fdisk ${QEMU_DISK_IMAGE} << EOF
+o
+n
+
+
+
+
+a
+w
+EOF
+
+}
+
+
+mount_disk_image(){
+    echo "正在挂载磁盘镜像..."
+    TMP_LOOP_DEVICE=$(sudo losetup -f --show -P ${QEMU_DISK_IMAGE}) || exit 1
+
+    # 根据函数入参判断是否需要格式化磁盘镜像
+    if [ "$1" == "mnt" ]; then
+        mkdir -p ../output/mnt
+        sudo mount ${TMP_LOOP_DEVICE}p1 ../output/mnt
+    fi
+    
+    echo "挂载磁盘镜像完成"
+}
+
+umount_disk_image(){
+    echo "正在卸载磁盘镜像..."
+    if [ "$1" == "mnt" ]; then
+        sudo umount ../output/mnt
+    fi
+    sudo losetup -d ${TMP_LOOP_DEVICE} || (echo "卸载磁盘镜像失败" && exit 1)
+    echo "卸载磁盘镜像完成"
+}
+
+prepare_disk_image()
+{
+    # 如果磁盘镜像不存在,则创建磁盘镜像
+    
+    echo "正在准备磁盘镜像..."
+    if [ ! -f ${QEMU_DISK_IMAGE} ]; then
+        echo "正在创建磁盘镜像..."
+        qemu-img create -f raw ${QEMU_DISK_IMAGE} 256M || (echo "创建磁盘镜像失败" && exit 1)
+        format_as_mbr
+
+        mount_disk_image
+        echo "loop device: ${TMP_LOOP_DEVICE}"
+        echo "正在格式化磁盘镜像..."
+        sudo mkfs.vfat -F 32 ${TMP_LOOP_DEVICE}p1
+        umount_disk_image
+
+        echo "Successfully mkfs"
+
+        chmod 777 ${QEMU_DISK_IMAGE}
+
+        echo "创建磁盘镜像完成"
+    fi
+    echo "磁盘镜像已经准备好"
+}
+
+
+write_disk_image(){
+    mkdir -p ../output/sysroot
+    echo "正在写入磁盘镜像..."
+    mount_disk_image mnt
+
+    mkdir -p ../output/sysroot/efi/boot
+    if [ ${ARCH} == "riscv64" ]; then
+        cp ../output/dragon_boot-riscv64imac.efi ../output/sysroot/efi/boot/bootriscv64.efi
+    fi
+
+    sudo cp -r ../output/sysroot/* ../output/mnt
+    
+    umount_disk_image mnt
+    echo "写入磁盘镜像完成"
+
+}
+
+main()
+{
+    install_riscv_uboot
+    prepare_disk_image
+    write_disk_image
+    run_qemu
+}
+
+main