Skip to content

Commit ac95724

Browse files
committed
hyperv reset
1 parent d3c9492 commit ac95724

File tree

18 files changed

+512
-291
lines changed

18 files changed

+512
-291
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9262,7 +9262,6 @@ dependencies = [
92629262
"tracing",
92639263
"unix_socket",
92649264
"vm_resource",
9265-
"vmm_core_defs",
92669265
"vmm_test_macros",
92679266
"vtl2_settings_proto",
92689267
"x86defs",

petri/petri_artifacts_common/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub mod tags {
7272
/// This is necessary because some guests will ignore shutdown requests
7373
/// that arrive too early in the boot process.
7474
pub hyperv_shutdown_ic_sleep: Option<std::time::Duration>,
75+
/// Some guests reboot automatically soon after first boot.
76+
pub initial_reboot_required: bool,
7577
}
7678

7779
/// Artifact is a OpenHCL IGVM file

petri/src/vm/hyperv/hyperv.psm1

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,4 +432,20 @@ function Get-VmScreenshot
432432
[IO.File]::WriteAllBytes($Path, $image.ImageData)
433433

434434
return "$x,$y"
435+
}
436+
437+
function Set-TurnOffOnGuestRestart
438+
{
439+
[CmdletBinding()]
440+
Param (
441+
[Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
442+
[System.Object]
443+
$Vm,
444+
445+
[bool] $Enable
446+
)
447+
448+
$vssd = Get-Vssd $Vm
449+
$vssd.TurnOffOnGuestRestart = $Enable
450+
Set-VmSystemSettings $vssd
435451
}

petri/src/vm/hyperv/mod.rs

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ use crate::IsolationType;
1313
use crate::NoPetriVmInspector;
1414
use crate::OpenHclConfig;
1515
use crate::OpenHclServicingFlags;
16+
use crate::PetriHaltReason;
1617
use crate::PetriVmConfig;
17-
use crate::PetriVmFramebufferAccess;
1818
use crate::PetriVmResources;
1919
use crate::PetriVmRuntime;
2020
use crate::PetriVmmBackend;
2121
use crate::SecureBootTemplate;
2222
use crate::ShutdownKind;
2323
use crate::UefiConfig;
24-
use crate::VmScreenshotMeta;
2524
use crate::disk_image::AgentImage;
2625
use crate::hyperv::powershell::HyperVSecureBootTemplate;
2726
use crate::kmsg_log_task;
@@ -43,22 +42,18 @@ use petri_artifacts_common::tags::OsFlavor;
4342
use petri_artifacts_core::ArtifactResolver;
4443
use petri_artifacts_core::ResolvedArtifact;
4544
use pipette_client::PipetteClient;
46-
use std::fs;
4745
use std::io::ErrorKind;
4846
use std::io::Write;
4947
use std::path::Path;
50-
use std::sync::Arc;
51-
use std::sync::Weak;
5248
use std::time::Duration;
5349
use vm::HyperVVM;
54-
use vmm_core_defs::HaltReason;
5550

5651
/// The Hyper-V Petri backend
5752
pub struct HyperVPetriBackend {}
5853

5954
/// Resources needed at runtime for a Hyper-V Petri VM
6055
pub struct HyperVPetriRuntime {
61-
vm: Arc<HyperVVM>,
56+
vm: HyperVVM,
6257
log_tasks: Vec<Task<anyhow::Result<()>>>,
6358
temp_dir: tempfile::TempDir,
6459
is_openhcl: bool,
@@ -71,7 +66,14 @@ impl PetriVmmBackend for HyperVPetriBackend {
7166
type VmmConfig = ();
7267
type VmRuntime = HyperVPetriRuntime;
7368

74-
fn check_compat(firmware: &Firmware, arch: MachineArch) -> bool {
69+
fn check_compat(firmware: &mut Firmware, arch: MachineArch) -> bool {
70+
// Workaround for Ubuntu OpenHCL Hyper-V VMs automatically resetting
71+
if matches!(firmware.os_flavor(), OsFlavor::Linux) && firmware.is_openhcl() {
72+
if let Some(quirks) = firmware.quirks_mut() {
73+
quirks.initial_reboot_required = true;
74+
}
75+
}
76+
7577
arch == MachineArch::host()
7678
&& !firmware.is_linux_direct()
7779
&& !(firmware.is_pcat() && arch == MachineArch::Aarch64)
@@ -292,7 +294,7 @@ impl PetriVmmBackend for HyperVPetriBackend {
292294
// location at runtime.
293295
let imc_hive = temp_dir.path().join("imc.hiv");
294296
{
295-
let mut imc_hive_file = fs::File::create_new(&imc_hive)?;
297+
let mut imc_hive_file = fs_err::File::create_new(&imc_hive)?;
296298
imc_hive_file
297299
.write_all(include_bytes!("../../../guest-bootstrap/imc.hiv"))
298300
.context("failed to write imc hive")?;
@@ -427,7 +429,7 @@ impl PetriVmmBackend for HyperVPetriBackend {
427429
vm.start().await?;
428430

429431
Ok(HyperVPetriRuntime {
430-
vm: Arc::new(vm),
432+
vm,
431433
log_tasks,
432434
temp_dir,
433435
is_openhcl: openhcl_config.is_some(),
@@ -440,19 +442,15 @@ impl PetriVmmBackend for HyperVPetriBackend {
440442
#[async_trait]
441443
impl PetriVmRuntime for HyperVPetriRuntime {
442444
type VmInspector = NoPetriVmInspector;
443-
type VmFramebufferAccess = HyperVFramebufferAccess;
445+
type VmFramebufferAccess = vm::HyperVFramebufferAccess;
444446

445447
async fn teardown(mut self) -> anyhow::Result<()> {
446448
futures::future::join_all(self.log_tasks.into_iter().map(|t| t.cancel())).await;
447-
Arc::into_inner(self.vm)
448-
.context("all references to the Hyper-V VM object have not been closed")?
449-
.remove()
450-
.await
449+
self.vm.remove().await
451450
}
452451

453-
async fn wait_for_halt(&mut self) -> anyhow::Result<HaltReason> {
454-
self.vm.wait_for_halt().await?;
455-
Ok(HaltReason::PowerOff) // TODO: Get actual halt reason
452+
async fn wait_for_halt(&mut self, allow_reset: bool) -> anyhow::Result<PetriHaltReason> {
453+
self.vm.wait_for_halt(allow_reset).await
456454
}
457455

458456
async fn wait_for_agent(&mut self, set_high_vtl: bool) -> anyhow::Result<PipetteClient> {
@@ -531,26 +529,8 @@ impl PetriVmRuntime for HyperVPetriRuntime {
531529
self.vm.restart_openhcl(flags).await
532530
}
533531

534-
fn take_framebuffer_access(&mut self) -> Option<HyperVFramebufferAccess> {
535-
(!self.is_isolated).then(|| HyperVFramebufferAccess {
536-
vm: Arc::downgrade(&self.vm),
537-
})
538-
}
539-
}
540-
541-
/// Interface to the Hyper-V framebuffer
542-
pub struct HyperVFramebufferAccess {
543-
vm: Weak<HyperVVM>,
544-
}
545-
546-
#[async_trait]
547-
impl PetriVmFramebufferAccess for HyperVFramebufferAccess {
548-
async fn screenshot(&mut self, image: &mut Vec<u8>) -> anyhow::Result<VmScreenshotMeta> {
549-
self.vm
550-
.upgrade()
551-
.context("VM no longer exists")?
552-
.screenshot(image)
553-
.await
532+
fn take_framebuffer_access(&mut self) -> Option<vm::HyperVFramebufferAccess> {
533+
(!self.is_isolated).then(|| self.vm.get_framebuffer_access())
554534
}
555535
}
556536

@@ -644,13 +624,13 @@ async fn hyperv_serial_log_task(
644624
) -> anyhow::Result<()> {
645625
let mut timer = None;
646626
loop {
647-
match fs_err::OpenOptions::new()
627+
match std::fs::OpenOptions::new()
648628
.read(true)
649629
.write(true)
650630
.open(&serial_pipe_path)
651631
{
652632
Ok(file) => {
653-
let pipe = PolledPipe::new(&driver, file.into()).expect("failed to create pipe");
633+
let pipe = PolledPipe::new(&driver, file).expect("failed to create pipe");
654634
// connect/disconnect messages logged internally
655635
_ = crate::log_task(log_file.clone(), pipe, &serial_pipe_path).await;
656636
}
@@ -661,7 +641,7 @@ async fn hyperv_serial_log_task(
661641
if !(err.kind() == ErrorKind::NotFound
662642
|| matches!(err.raw_os_error(), Some(ERROR_PIPE_BUSY)))
663643
{
664-
tracing::warn!("{err:#}")
644+
tracing::warn!("failed to open {serial_pipe_path}: {err:#}",)
665645
}
666646
// Wait a bit and try again.
667647
timer

0 commit comments

Comments
 (0)