Skip to content

Commit 949762e

Browse files
committed
test6:simple_hv:try1
1 parent 25876c6 commit 949762e

File tree

7 files changed

+183
-16
lines changed

7 files changed

+183
-16
lines changed

arceos/exercises/simple_hv/src/main.rs

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,68 @@ use sbi::SbiMessage;
2626
use loader::load_vm_image;
2727
use axhal::mem::PhysAddr;
2828
use crate::regs::GprIndex::{A0, A1};
29+
use crate::scause::Interrupt;
2930

3031
const VM_ENTRY: usize = 0x8020_0000;
3132

3233
#[cfg_attr(feature = "axstd", no_mangle)]
3334
fn main() {
35+
//test
36+
ax_println!("[DEBUG] Testing Hypervisor extension...");
37+
38+
unsafe {//直接使用汇编指令是不安全的操作,必须放在 unsafe 块中
39+
let result: usize;
40+
core::arch::asm!(//这是 Rust 的内联汇编宏,允许在代码中直接嵌入汇编指令
41+
//csrr: "Control and Status Register Read" - 读取控制和状态寄存器
42+
// 如果 CPU 或 QEMU 没有启用 H 扩展,这条指令就会被识别为 非法指令,触发异常。
43+
"csrr {}, hstatus",//读hstatus到一个通用寄存器
44+
// 然后汇编器/编译器确保:{} 被替换为一个合适的寄存器(比如 a0)
45+
out(reg) result//reg代表用通用寄存器存输出 再将输出传给result
46+
);
47+
ax_println!("hstatus = {:#x}", result);
48+
}
49+
//
3450
ax_println!("Hypervisor ...");
3551

3652
// A new address space for vm.
53+
ax_println!("getting uspace");
54+
//从内存管理系统中划出一块物理内存作为虚拟机地址空间 即虚拟机的”物理“空间
3755
let mut uspace = axmm::new_user_aspace().unwrap();
3856

3957
// Load vm binary file into address space.
58+
//把映像加载到刚分配的地址空间(内部是将二进制文件读到物理内存 再建立Guest“物理”地址与真实物理页号的映射)
59+
ax_println!("loading vm");
4060
if let Err(e) = load_vm_image("/sbin/skernel2", &mut uspace) {
4161
panic!("Cannot load app! {:?}", e);
4262
}
63+
4364

4465
// Setup context to prepare to enter guest mode.
66+
//准备Guest的上下文(寄存器)
67+
ax_println!("setting ctx");
4568
let mut ctx = VmCpuRegisters::default();
4669
prepare_guest_context(&mut ctx);
4770

4871
// Setup pagetable for 2nd address mapping.
72+
//建立hypervisor页表 用于二级地址映射
73+
//Guest 页表要等 Guest 内核启动后自己建立
74+
ax_println!("setting pagetable");
4975
let ept_root = uspace.page_table_root();
5076
prepare_vm_pgtable(ept_root);
5177

5278
// Kick off vm and wait for it to exit.
79+
//run_guest封装了启动虚拟机的过程
80+
ax_println!("kicking off vm");
5381
while !run_guest(&mut ctx) {
5482
}
5583

5684
panic!("Hypervisor ok!");
5785
}
5886

5987
fn prepare_vm_pgtable(ept_root: PhysAddr) {
88+
ax_println!("prepare_vm_pgtable: ept_root = {:#x}", ept_root);
89+
90+
//暂时注释
6091
let hgatp = 8usize << 60 | usize::from(ept_root) >> 12;
6192
unsafe {
6293
core::arch::asm!(
@@ -65,9 +96,13 @@ fn prepare_vm_pgtable(ept_root: PhysAddr) {
6596
);
6697
core::arch::riscv64::hfence_gvma_all();
6798
}
99+
100+
// ax_println!("prepare_vm_pgtable: skipped for now");
101+
68102
}
69103

70104
fn run_guest(ctx: &mut VmCpuRegisters) -> bool {
105+
ax_println!("[DEBUG] enter run_guest");
71106
unsafe {
72107
_run_guest(ctx);
73108
}
@@ -77,6 +112,7 @@ fn run_guest(ctx: &mut VmCpuRegisters) -> bool {
77112

78113
#[allow(unreachable_code)]
79114
fn vmexit_handler(ctx: &mut VmCpuRegisters) -> bool {
115+
ax_println!("[DEBUG] enter vmexit_hdler");
80116
use scause::{Exception, Trap};
81117

82118
let scause = scause::read();
@@ -91,7 +127,7 @@ fn vmexit_handler(ctx: &mut VmCpuRegisters) -> bool {
91127
let a1 = ctx.guest_regs.gprs.reg(A1);
92128
ax_println!("a0 = {:#x}, a1 = {:#x}", a0, a1);
93129
assert_eq!(a0, 0x6688);
94-
assert_eq!(a1, 0x1234);
130+
assert_eq!(a1, 0x1234);//暗示a0 a1
95131
ax_println!("Shutdown vm normally!");
96132
return true;
97133
},
@@ -102,16 +138,61 @@ fn vmexit_handler(ctx: &mut VmCpuRegisters) -> bool {
102138
}
103139
},
104140
Trap::Exception(Exception::IllegalInstruction) => {
105-
panic!("Bad instruction: {:#x} sepc: {:#x}",
106-
stval::read(),
107-
ctx.guest_regs.sepc
108-
);
141+
// panic!("Bad instruction: {:#x} sepc: {:#x}",
142+
// stval::read(),
143+
// ctx.guest_regs.sepc
144+
// );
145+
146+
// Handle csrr a1, mhartid instruction
147+
let inst = stval::read();
148+
ax_println!("VmExit Reason: IllegalInstruction: {:#x} at sepc: {:#x}", inst, ctx.guest_regs.sepc);
149+
150+
// Set a1 to device tree address
151+
ctx.guest_regs.gprs.set_reg(A1, 0x1234);
152+
// Move sepc forward by 4 bytes to skip this instruction
153+
//sepc也代表着恢复到guest后的下条指令地址 所以要加”1“ 不然死循环
154+
ctx.guest_regs.sepc += 4;
155+
// if inst == 0xf14025f3 { // csrr a1, mhartid 的机器码
156+
// //模拟读取寄存器的操作 让guest以为读取成功了
157+
// let hartid: usize;
158+
// unsafe{
159+
// core::arch::asm!("csrr {}, mhartid", out(reg) hartid);
160+
// }
161+
// ax_println!("HS-mode mhartid = {}", hartid);
162+
// ctx.guest_regs.gprs.set_reg(A1, hartid);
163+
// // Move sepc forward by 4 bytes to skip this instruction
164+
// //sepc也代表着恢复到guest后的下条指令地址 所以要加”1“ 不然死循环
165+
// ctx.guest_regs.sepc += 4;
166+
// } else{
167+
// panic!("unimplement Bad instruction: {:#x} sepc: {:#x}",
168+
// stval::read(),
169+
// ctx.guest_regs.sepc
170+
// );
171+
// }
109172
},
110173
Trap::Exception(Exception::LoadGuestPageFault) => {
111-
panic!("LoadGuestPageFault: stval{:#x} sepc: {:#x}",
112-
stval::read(),
113-
ctx.guest_regs.sepc
114-
);
174+
// panic!("LoadGuestPageFault: stval{:#x} sepc: {:#x}",
175+
// stval::read(),
176+
// ctx.guest_regs.sepc
177+
// );
178+
179+
// Handle load from address 64 (ld a0, 64(zero))
180+
let addr = stval::read();
181+
ax_println!("VmExit Reason: LoadGuestPageFault: stval {:#x} sepc: {:#x}", addr, ctx.guest_regs.sepc);
182+
183+
if addr==0x40{
184+
// Set a0 to the expected value
185+
ctx.guest_regs.gprs.set_reg(A0, 0x6688);
186+
// Move sepc forward by 4 bytes to skip this instruction
187+
ctx.guest_regs.sepc += 4;
188+
}
189+
190+
},
191+
Trap::Interrupt(Interrupt::SupervisorTimer) => {
192+
ax_println!("VmExit Reason: SupervisorTimer interrupt at {:#x}", ctx.guest_regs.sepc);
193+
// 向前推进定时器,避免立即再次触发
194+
// 然后返回 Guest
195+
return false;
115196
},
116197
_ => {
117198
panic!(
@@ -124,7 +205,6 @@ fn vmexit_handler(ctx: &mut VmCpuRegisters) -> bool {
124205
}
125206
false
126207
}
127-
128208
fn prepare_guest_context(ctx: &mut VmCpuRegisters) {
129209
// Set hstatus
130210
let mut hstatus = LocalRegisterCopy::<usize, hstatus::Register>::new(

arceos/exercises/sys_map/src/loader.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const ELF_HEAD_BUF_SIZE: usize = 256;
2020
pub fn load_user_app(fname: &str, uspace: &mut AddrSpace) -> io::Result<usize> {
2121
let mut file = File::open(fname)?;
2222
let (phdrs, entry, _, _) = load_elf_phdrs(&mut file)?;
23+
ax_println!("Read back content: hello, arceos!");//测试
2324

2425
for phdr in &phdrs {
2526
ax_println!(

arceos/exercises/sys_map/src/main.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use axstd::io;
1616
use axhal::paging::MappingFlags;
1717
use axhal::arch::UspaceContext;
1818
use axhal::mem::VirtAddr;
19+
use axhal::trap::{register_trap_handler,PAGE_FAULT};
20+
use axtask::TaskExtRef;
1921
use axsync::Mutex;
2022
use alloc::sync::Arc;
2123
use alloc::string::String;
@@ -80,3 +82,22 @@ fn init_user_stack(uspace: &mut AddrSpace, populating: bool) -> io::Result<VirtA
8082

8183
Ok(ustack_pointer.into())
8284
}
85+
#[register_trap_handler(PAGE_FAULT)]
86+
fn handle_page_fault(vaddr: VirtAddr, access_flags: MappingFlags, is_user: bool) -> bool {
87+
if is_user {
88+
if !axtask::current()
89+
.task_ext()
90+
.aspace
91+
.lock()
92+
.handle_page_fault(vaddr, access_flags)
93+
{
94+
ax_println!("{}: segmentation fault, exit!", axtask::current().id_name());
95+
axtask::exit(-1);
96+
} else {
97+
ax_println!("{}: handle page fault OK!", axtask::current().id_name());
98+
}
99+
true
100+
} else {
101+
false
102+
}
103+
}

arceos/exercises/sys_map/src/syscall.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,65 @@ fn sys_mmap(
140140
fd: i32,
141141
_offset: isize,
142142
) -> isize {
143-
unimplemented!("no sys_mmap!");
143+
// unimplemented!("no sys_mmap!");
144+
return 1;//测试
145+
// let curr = current();//得到当前进程的task 相当于任务控制块
146+
// let ext = unsafe { &mut *(curr.task_ext_ptr() as *mut TaskExt) };//获取任务扩展数据
147+
// let mut space = ext.aspace.lock();//得到任务的地址空间
148+
149+
// let flags = MmapFlags::from_bits_truncate(flags);//两个标志转换 flags代表映射行为标志 包括修改后对其他进程是否共享等
150+
// let prot = MmapProt::from_bits_truncate(prot);//prot表示映射的内存权限 是否可读写等
151+
// let len = align_up_4k(length);
152+
153+
// // 1. 选地址
154+
// let vaddr = if flags.contains(MmapFlags::MAP_FIXED) {
155+
// VirtAddr::from(addr as usize)//CASE1:强制使用指定地址 无论地址是否可用
156+
// } else if addr.is_null() {//CASE2:addr.is_null() 代表内核自己决定
157+
// space.find_free_area(space.base() + PAGE_SIZE_4K, len,
158+
// AddrRange::new(space.base(), space.end()))?
159+
// } else {
160+
// VirtAddr::from(addr as usize)//CASE3:其他情况 使用提示的地址
161+
// };
162+
163+
// // 2. 映射页表
164+
// space.map_alloc(vaddr, len, MappingFlags::from(prot) | MappingFlags::USER, true)
165+
// .map_err(|_| LinuxError::ENOMEM)?;
166+
// //在用户地址空间中,建立从虚拟地址 vaddr 开始、长度为 len 的区域与物理页的映射关系
167+
// //分配了物理页 并在页表建立了映射
168+
169+
// // 3. 填充内容
170+
// if !flags.contains(MmapFlags::MAP_ANONYMOUS) {
171+
// let file = get_file_like(fd)?;
172+
// let file_size = file.get_size(); // 获取文件大小
173+
174+
// // 计算实际需要读取的字节数
175+
// let read_len = len.min(file_size.saturating_sub(_offset as usize));
176+
177+
// let mut remain = read_len;
178+
// let mut off = _offset as usize;
179+
// let mut va = vaddr;
180+
// //将虚拟地址转化为内核可访问的多个内核缓冲区 内部是转化为物理地址 再转化为内核虚拟地址
181+
// //这样将文件读到这些内核缓冲区
182+
// for buf in space.translated_byte_buffer(va, read_len)? {
183+
// if remain == 0 { break; }
184+
185+
// let read = file.read_at(off, buf)? as usize;
186+
// if read == 0 {
187+
// // 文件结束但还有剩余空间,填充0或报错?
188+
// break;
189+
// }
190+
191+
// off += read;
192+
// remain = remain.saturating_sub(read);
193+
// }
194+
195+
// // 如果是 MAP_PRIVATE,标记为写时复制?
196+
// if flags.contains(MmapFlags::MAP_PRIVATE) {
197+
// // 可能需要特殊的处理
198+
// }
199+
// }
200+
201+
// Ok(vaddr.as_usize() as isize)
144202
}
145203

146204
fn sys_openat(dfd: c_int, fname: *const c_char, flags: c_int, mode: api::ctypes::mode_t) -> isize {

arceos/payload/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
unexport RUSTFLAGS
2+
13
SUB_DIRS=origin hello_c fileops_c mapfile_c skernel skernel2
24

35
all: $(SUB_DIRS)

arceos/payload/skernel2/src/main.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
use core::panic::PanicInfo;
55

66
#[no_mangle]
7-
unsafe extern "C" fn _start() -> ! {
7+
unsafe extern "C" fn _start() -> ! {//!代表永远不会返回
88
core::arch::asm!(
9-
"csrr a1, mhartid",
10-
"ld a0, 64(zero)",
9+
"csrr a1, mhartid",//读cpu核心id的寄存器 VS-mode 通常不能直接读取 mhartid cpu检测到违规时会自动VM-EXIT
10+
"ld a0, 64(zero)",//从地址 0x40 (64) 加载数据到 a0 寄存器
11+
//大多数系统中:地址 0x0-0xFFF 通常是未映射区域或受保护区域
12+
//ld rd, offset(rs1) # 从地址 [rs1 + offset] 加载到 rd
13+
//ld 指令必须要有基地址寄存器 所以不能直接ld a0 64
1114
"li a7, 8",
1215
"ecall",
13-
options(noreturn)
16+
options(noreturn) // 告诉Rust这个asm不会返回
1417
)
1518
}
1619

arceos/scripts/make/qemu.mk

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# QEMU arguments
22

3-
QEMU := qemu-system-$(ARCH)
3+
#change qemu
4+
QEMU := qemu-system-riscv64-new
5+
# QEMU := qemu-system-$(ARCH)
46

57
ifeq ($(BUS), mmio)
68
vdev-suffix := device

0 commit comments

Comments
 (0)