M1 macOS下Hypervisor Framework的hv_vcpu_run无法返回问题
基于Hypervisor Framework开发虚拟机管理器时
hv_vcpu_run无法返回的问题 我在基于Hypervisor Framework开发虚拟机管理器时,遇到hv_vcpu_run始终无法返回的问题。按预期,待执行代码会触发MMIO操作,该函数应当返回。相同代码在Asahi Linux的KVM环境中测试时,KVM_RUN可正常返回KVM_EXIT_MMIO,符合预期。
vCPU配置代码
// 设置PSTATE。 states.set_pstate( Pstate::new() .with_m(0b0101) // EL1,使用SP_EL1(EL1h)。 .with_f(true) .with_i(true) .with_a(true) .with_d(true), ); // 启用MMU以支持虚拟地址,并设置TCR_EL1。 states.set_sctlr( Sctlr::new() .with_m(true) .with_c(true) .with_itd(true) .with_i(true) .with_tscxt(true) .with_span(true) .with_ntlsmd(true) .with_lsmaoe(true), ); states.set_mair_el1(map.memory_attrs); states.set_tcr( Tcr::new() .with_ips(feats.mmfr0.pa_range()) .with_tg1(match map.page_size.get() { 0x4000 => 0b01, // TTBR1_EL1使用16K页。 _ => todo!(), }) .with_sh1(0b11) .with_orgn1(0b01) .with_irgn1(0b01) .with_t1sz(16) .with_tg0(match map.page_size.get() { 0x4000 => 0b10, // TTBR0_EL1使用16K页。 _ => todo!(), }) .with_sh0(0b11) .with_orgn0(0b01) .with_irgn0(0b01) .with_t0sz(16), ); // 设置页表。由于虚拟设备使用恒等映射,需要同时设置低地址和高地址VA。 states.set_ttbr0_el1(map.page_table); states.set_ttbr1_el1(map.page_table); // 设置入口点、参数和栈指针。 states.set_x0(map.env_vaddr); states.set_x1(map.conf_vaddr); states.set_sp_el1(map.stack_vaddr + map.stack_len); // 栈向下增长。 states.set_pc(map.kern_vaddr + entry); states .commit() .map_err(|e| MainCpuError::CommitCpuStatesFailed(Box::new(e)))
commit方法实现
fn commit(self) -> Result<(), Self::Err> { use hv_sys::{ hv_reg_t_HV_REG_CPSR as HV_REG_CPSR, hv_reg_t_HV_REG_PC as HV_REG_PC, hv_reg_t_HV_REG_X0 as HV_REG_X0, hv_reg_t_HV_REG_X1 as HV_REG_X1, hv_sys_reg_t_HV_SYS_REG_MAIR_EL1 as HV_SYS_REG_MAIR_EL1, hv_sys_reg_t_HV_SYS_REG_SCTLR_EL1 as HV_SYS_REG_SCTLR_EL1, hv_sys_reg_t_HV_SYS_REG_SP_EL1 as HV_SYS_REG_SP_EL1, hv_sys_reg_t_HV_SYS_REG_TCR_EL1 as HV_SYS_REG_TCR_EL1, hv_sys_reg_t_HV_SYS_REG_TTBR0_EL1 as HV_SYS_REG_TTBR0_EL1, hv_sys_reg_t_HV_SYS_REG_TTBR1_EL1 as HV_SYS_REG_TTBR1_EL1, hv_vcpu_set_reg, hv_vcpu_set_sys_reg, }; // 设置PSTATE。Hypervisor Framework使用CPSR表示PSTATE。 let cpu = self.cpu.instance; let set_reg = |reg, val| match NonZero::new(unsafe { hv_vcpu_set_reg(cpu, reg, val) }) { Some(v) => Err(v), None => Ok(()), }; if let State::Dirty(v) = self.pstate { set_reg(HV_REG_CPSR, v).map_err(StatesError::SetPstateFailed)?; } // 设置系统寄存器。 let set_sys = |reg, val| match NonZero::new(unsafe { hv_vcpu_set_sys_reg(cpu, reg, val) }) { Some(v) => Err(v), None => Ok(()), }; if let State::Dirty(v) = self.mair_el1 { set_sys(HV_SYS_REG_MAIR_EL1, v).map_err(StatesError::SetMairEl1Failed)?; } if let State::Dirty(v) = self.ttbr0_el1 { set_sys(HV_SYS_REG_TTBR0_EL1, v).map_err(StatesError::SetTtbr0El1Failed)?; } if let State::Dirty(v) = self.ttbr1_el1 { set_sys(HV_SYS_REG_TTBR1_EL1, v).map_err(StatesError::SetTtbr1El1Failed)?; } if let State::Dirty(v) = self.tcr { set_sys(HV_SYS_REG_TCR_EL1, v).map_err(StatesError::SetTcrFailed)?; } if let State::Dirty(v) = self.sctlr { set_sys(HV_SYS_REG_SCTLR_EL1, v).map_err(StatesError::SetSctlrFailed)?; } if let State::Dirty(v) = self.sp_el1 { set_sys(HV_SYS_REG_SP_EL1, v).map_err(StatesError::SetSpEl1Failed)?; } // 设置通用寄存器。 if let State::Dirty(v) = self.pc { set_reg(HV_REG_PC, v).map_err(StatesError::SetPcFailed)?; } if let State::Dirty(v) = self.x0 { set_reg(HV_REG_X0, v).map_err(StatesError::SetX0Failed)?; } if let State::Dirty(v) = self.x1 { set_reg(HV_REG_X1, v).map_err(StatesError::SetX1Failed)?; } Ok(()) }
内容的提问来源于stack exchange,提问作者user1829232
相关产品推荐
相关产品推荐

