Skip to content
This repository was archived by the owner on Feb 7, 2026. It is now read-only.

Commit 6e9a49f

Browse files
authored
feat(main): Add virtio-block device support, adjust ramdisk interface content, and unify the external API interface of boot media (#7)
- Add virtio-block device support, implemented by encapsulating related interfaces of axfs - Modify ramdisk-cpio related interfaces and open them to the public - Shield the differences between different boot media and unify the medium API interface Signed-off-by: JensenWei007 <jensenwei007@gmail.com>
1 parent bbc2348 commit 6e9a49f

File tree

11 files changed

+198
-106
lines changed

11 files changed

+198
-106
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ rustsbi/
3030

3131
/.axconfig.*
3232

33-
*.cpio
33+
*.cpio

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ edition = "2024"
55
authors = ["Zhihang Shao <dio_ro@outlook.com>", "Jingxuan Wei <jensenwei007@gmail.com>"]
66

77
[features]
8-
default = ["alloc", "fs", "paging", "ramdisk_cpio"]
8+
default = ["alloc", "fs", "paging", "virtiodisk"]
99

1010
alloc = ["axalloc"]
1111
paging = ["axhal/paging", "axmm"]
@@ -15,7 +15,6 @@ net = ["axdriver", "axnet"]
1515
display = ["axdriver", "axdisplay"]
1616

1717
# Boot Media
18-
1918
virtiodisk = ["axdriver/virtio-blk"]
2019
ramdisk_cpio = []
2120

@@ -35,3 +34,4 @@ ctor_bare = "0.2"
3534
cfg-if = "1.0"
3635

3736
chrono = { version = "0.4.38", default-features = false }
37+
axio = { version = "0.1", features = ["alloc"] }

Makefile

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# - `PLATFORM`: Target platform in the `platforms` directory
55
# - `SMP`: Number of CPUs
66
# - `LOG:` Logging level: warn, error, info, debug, trace
7-
# - `MEDIA:` Boot Media Type: ramdisk-cpio, virtio-blk
7+
# - `MEDIUM:` Boot Medium Type: ramdisk-cpio, virtio-blk
88
# - `EXTRA_CONFIG`: Extra config specification file
99
# - `OUT_CONFIG`: Final config file that takes effect
1010
# * QEMU options:
@@ -16,13 +16,15 @@ ARCH ?= riscv64
1616
PLATFORM ?=
1717
SMP ?= 1
1818
LOG ?= debug
19-
MEDIA ?= ramdisk-cpio
19+
20+
# 下面的目前还没用, 现在需要手动去cargo.toml中修改, 后面补上
21+
MEDIUM ?= ramdisk-cpio
2022

2123
OUT_CONFIG ?= $(PWD)/.axconfig.toml
2224
EXTRA_CONFIG ?=
2325

2426
# QEMU options
25-
DISK:= fat32_disk_test.img
27+
DISK:= disk.img
2628
SBI:=rustsbi/target/riscv64imac-unknown-none-elf/release/rustsbi-prototyper-payload.elf
2729
RAMDISK_CPIO:=ramdisk.cpio
2830

@@ -50,5 +52,5 @@ build: clean defconfig all
5052
ramdiskcpio:
5153
qemu-system-riscv64 -m 128M -serial mon:stdio -bios $(SBI) -nographic -machine virt -device loader,file=$(RAMDISK_CPIO),addr=0x84000000
5254

53-
run:
54-
qemu-system-riscv64 -m 128M -serial mon:stdio -bios $(SBI) -nographic -machine virt -device virtio-blk-pci,drive=disk0 -drive id=disk0,if=none,format=raw,file=$(DISK)
55+
virtiodisk:
56+
qemu-system-riscv64 -m 128M -serial mon:stdio -bios $(SBI) -nographic -machine virt -device virtio-blk-pci,drive=disk0 -drive id=disk0,if=none,format=raw,file=$(DISK)

scripts/test/disk.sh

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
#!/bin/bash
22
set -e
33

4-
IMG_NAME="fat32_disk_test.img"
5-
IMG_SIZE_MB=512
6-
MOUNT_DIR="mnt_fat32"
4+
print_info() {
5+
printf "\033[1;37m%s\033[0m" "[RustSBI-Arceboot Build For Test] "
6+
printf "\033[1;32m%s\033[0m" "[INFO] "
7+
printf "\033[36m%s\033[0m\n" "$1"
8+
}
79

8-
echo "[1/2] 创建空镜像文件..."
9-
dd if=/dev/zero of=$IMG_NAME bs=1M count=$IMG_SIZE_MB
10+
print_info "开始执行 virtio-block 类型的 disk 创建脚本"
11+
print_info "此为 FAT32 文件系统镜像, 只含有一个 arceboot.txt 文件, 用于测试 Arceboot"
12+
print_info "即将在当前目录执行创建 -------->"
1013

11-
echo "[2/2] 格式化为 FAT32 文件系统..."
12-
mkfs.vfat -F 32 $IMG_NAME
14+
dd if=/dev/zero of=disk.img bs=1M count=512
15+
mkfs.vfat -F 32 disk.img
1316

14-
echo "======== DONE ========"
17+
mkdir temp
18+
sudo mount -o loop disk.img temp
19+
mkdir -p temp/test
20+
touch temp/test/arceboot.txt
21+
echo "This is a test file for Arceboot." > temp/test/arceboot.txt
22+
sudo umount temp
23+
rm -rf temp
24+
25+
print_info "创建完成, 生成的 disk.img 位于当前目录"

scripts/test/ramdisk_cpio.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ print_info "此为空镜像, 只含有一个 arceboot.txt 文件, 用于测试 A
1212
print_info "即将在当前目录执行创建 -------->"
1313

1414
mkdir myramdisk
15-
touch myramdisk/arceboot.txt
16-
echo "This is a test file for Arceboot." > myramdisk/arceboot.txt
15+
mkdir myramdisk/test
16+
touch myramdisk/test/arceboot.txt
17+
echo "This is a test file for Arceboot." > myramdisk/test/arceboot.txt
1718

1819
cd myramdisk
1920
find . | cpio -o --format=newc > ../ramdisk.cpio

src/main.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ extern crate axlog;
66

77
mod panic;
88
mod log;
9-
mod media;
9+
mod medium;
1010

1111
#[cfg_attr(not(test), unsafe(no_mangle))]
1212
pub extern "C" fn rust_main(_cpu_id: usize, _dtb: usize) -> ! {
@@ -42,7 +42,7 @@ pub extern "C" fn rust_main(_cpu_id: usize, _dtb: usize) -> ! {
4242
#[cfg(feature = "fs")]
4343
// 目前使用ramdisk的cpio格式时,驱动还不完善,用不了,需要注释掉
4444
// 如果使用virtio-blk驱动,则可以正常使用
45-
//axfs::init_filesystems(all_devices.block);
45+
axfs::init_filesystems(all_devices.block);
4646

4747
#[cfg(feature = "net")]
4848
axnet::init_network(all_devices.net);
@@ -52,9 +52,8 @@ pub extern "C" fn rust_main(_cpu_id: usize, _dtb: usize) -> ! {
5252
}
5353
ctor_bare::call_ctors();
5454

55-
info!("will test cpio.");
56-
57-
crate::media::parse_cpio_ramdisk();
55+
info!("current root dir: {}", crate::medium::current_dir().unwrap());
56+
info!("read test file context: {}", crate::medium::read_to_string("/test/arceboot.txt").unwrap());
5857

5958
info!("will shut down.");
6059

src/media/ramdisk_cpio.rs

Lines changed: 0 additions & 82 deletions
This file was deleted.

src/media/mod.rs renamed to src/medium/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ cfg_if::cfg_if! {
22
if #[cfg(feature = "ramdisk_cpio")] {
33
mod ramdisk_cpio;
44
pub use ramdisk_cpio::*;
5+
} else if #[cfg(feature = "virtiodisk")] {
6+
mod virtio_disk;
7+
pub use virtio_disk::*;
58
} else {
69
info!("Boot media feature is not enabled.");
710
}
8-
}
11+
}

src/medium/ramdisk_cpio.rs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
extern crate alloc;
2+
3+
use core::{ptr, str};
4+
use axhal::mem::phys_to_virt;
5+
use axio::{self as io, prelude::*};
6+
use alloc::{string::String, vec::Vec, string::ToString};
7+
8+
const CPIO_MAGIC: &[u8; 6] = b"070701";
9+
const CPIO_BASE: usize = 0x8400_0000;
10+
11+
#[repr(C)]
12+
#[derive(Debug)]
13+
struct CpioNewcHeader {
14+
c_magic: [u8; 6],
15+
c_ino: [u8; 8],
16+
c_mode: [u8; 8],
17+
c_uid: [u8; 8],
18+
c_gid: [u8; 8],
19+
c_nlink: [u8; 8],
20+
c_mtime: [u8; 8],
21+
c_filesize: [u8; 8],
22+
c_devmajor: [u8; 8],
23+
c_devminor: [u8; 8],
24+
c_rdevmajor: [u8; 8],
25+
c_rdevminor: [u8; 8],
26+
c_namesize: [u8; 8],
27+
c_check: [u8; 8],
28+
}
29+
30+
fn parse_hex_field(field: &[u8]) -> usize {
31+
// 将ASCII十六进制转换为数字
32+
let s = core::str::from_utf8(field).unwrap_or("0");
33+
usize::from_str_radix(s, 16).unwrap_or(0)
34+
}
35+
36+
fn align_up(addr: usize, align: usize) -> usize {
37+
(addr + align - 1) & !(align - 1)
38+
}
39+
40+
/// Returns the current working directory as a [`String`].
41+
pub fn current_dir() -> io::Result<String> {
42+
Ok("/".to_string())
43+
}
44+
45+
/// Read the entire contents of a file into a bytes vector.
46+
pub fn read(path: &str) -> io::Result<Vec<u8>> {
47+
let mut ptr = phys_to_virt(CPIO_BASE.into()).as_usize();
48+
49+
loop {
50+
let hdr = unsafe { &*(ptr as *const CpioNewcHeader) };
51+
52+
if &hdr.c_magic != CPIO_MAGIC {
53+
break;
54+
}
55+
56+
let namesize = parse_hex_field(&hdr.c_namesize);
57+
let filesize = parse_hex_field(&hdr.c_filesize);
58+
59+
let name_ptr = ptr + core::mem::size_of::<CpioNewcHeader>();
60+
let name = unsafe {
61+
let slice = core::slice::from_raw_parts(name_ptr as *const u8, namesize - 1);
62+
str::from_utf8(slice).unwrap_or("<invalid utf8>")
63+
};
64+
65+
if name == "TRAILER!!!" {
66+
break;
67+
}
68+
69+
let file_start = align_up(name_ptr + namesize, 4);
70+
let file_end = file_start + filesize;
71+
72+
let is_match = if path.starts_with('/') {
73+
&path[1..] == name
74+
} else {
75+
path == name
76+
};
77+
78+
if is_match {
79+
let data = unsafe {
80+
core::slice::from_raw_parts(file_start as *const u8, filesize)
81+
};
82+
let mut bytes = Vec::with_capacity(filesize as usize);
83+
bytes.extend_from_slice(data);
84+
return Ok(bytes);
85+
}
86+
87+
ptr = align_up(file_end, 4);
88+
}
89+
90+
core::prelude::v1::Err(io::Error::NotFound)
91+
}
92+
93+
/// Read the entire contents of a file into a string.
94+
pub fn read_to_string(path: &str) -> io::Result<String> {
95+
let mut ptr = phys_to_virt(CPIO_BASE.into()).as_usize();
96+
97+
loop {
98+
let hdr = unsafe { &*(ptr as *const CpioNewcHeader) };
99+
100+
if &hdr.c_magic != CPIO_MAGIC {
101+
break;
102+
}
103+
104+
let namesize = parse_hex_field(&hdr.c_namesize);
105+
let filesize = parse_hex_field(&hdr.c_filesize);
106+
107+
let name_ptr = ptr + core::mem::size_of::<CpioNewcHeader>();
108+
let name = unsafe {
109+
let slice = core::slice::from_raw_parts(name_ptr as *const u8, namesize - 1);
110+
str::from_utf8(slice).unwrap_or("<invalid utf8>")
111+
};
112+
113+
if name == "TRAILER!!!" {
114+
break;
115+
}
116+
117+
let file_start = align_up(name_ptr + namesize, 4);
118+
let file_end = file_start + filesize;
119+
120+
let is_match = if path.starts_with('/') {
121+
&path[1..] == name
122+
} else {
123+
path == name
124+
};
125+
126+
if is_match {
127+
let data = unsafe {
128+
let slice = core::slice::from_raw_parts(file_start as *const u8, filesize);
129+
str::from_utf8(slice).unwrap_or("<invalid utf8>")
130+
};
131+
return Ok(data.to_string());
132+
}
133+
134+
ptr = align_up(file_end, 4);
135+
}
136+
137+
core::prelude::v1::Err(io::Error::NotFound)
138+
}

0 commit comments

Comments
 (0)