Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(shutdown): always try qemu debug exit for error codes #1119

Merged
merged 4 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ multiboot = "0.8"
uart_16550 = "0.3"
x86 = { version = "0.52", default-features = false }
x86_64 = "0.15"
qemu-exit = "3.0"

[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64 = { version = "0.0", default-features = false }
Expand Down
8 changes: 1 addition & 7 deletions src/arch/x86_64/kernel/acpi.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use core::convert::Infallible;
use core::{mem, ptr, slice, str};

use align_address::Align;
use hermit_sync::OnceCell;
use x86::io::*;
use x86_64::structures::paging::PhysFrame;

use crate::arch::x86_64::kernel::processor;
use crate::arch::x86_64::mm::paging::{
BasePageSize, PageSize, PageTableEntryFlags, PageTableEntryFlagsExt,
};
Expand Down Expand Up @@ -446,7 +444,7 @@ pub fn get_madt() -> Option<&'static AcpiTable<'static>> {
MADT.get()
}

pub fn poweroff() -> Result<Infallible, ()> {
pub fn poweroff() {
if let (Some(&pm1a_cnt_blk), Some(&slp_typa)) = (PM1A_CNT_BLK.get(), SLP_TYPA.get()) {
let bits = (u16::from(slp_typa) << 10) | SLP_EN;
debug!(
Expand All @@ -456,12 +454,8 @@ pub fn poweroff() -> Result<Infallible, ()> {
unsafe {
outw(pm1a_cnt_blk, bits);
}
loop {
processor::halt();
}
} else {
warn!("ACPI Power Off is not available");
Err(())
}
}

Expand Down
49 changes: 20 additions & 29 deletions src/arch/x86_64/kernel/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ use core::arch::asm;
use core::arch::x86_64::{
__rdtscp, _fxrstor, _fxsave, _mm_lfence, _rdseed64_step, _rdtsc, _xrstor, _xsave,
};
use core::convert::Infallible;
use core::hint::spin_loop;
use core::num::NonZeroU32;
use core::sync::atomic::{AtomicU64, Ordering};
use core::{fmt, ptr, u32};

use hermit_entry::boot_info::PlatformInfo;
use hermit_sync::Lazy;
use qemu_exit::QEMUExit;
use x86::bits64::segmentation;
use x86::controlregs::*;
use x86::cpuid::*;
use x86::msr::*;
use x86_64::instructions::interrupts::int3;
use x86_64::instructions::port::Port;
use x86_64::instructions::tables::lidt;
use x86_64::structures::DescriptorTablePointer;
use x86_64::VirtAddr;
Expand Down Expand Up @@ -1028,38 +1027,30 @@ fn triple_fault() -> ! {
unreachable!()
}

fn qemu_exit(success: bool) {
let code = if success { 3 >> 1 } else { 0 };
unsafe {
Port::<u32>::new(0xf4).write(code);
}
}

/// Shutdown the system
pub fn shutdown(error_code: i32) -> ! {
info!("Shutting down system");
let acpi_result: Result<Infallible, ()> = {
#[cfg(feature = "acpi")]
{
acpi::poweroff()
}

#[cfg(not(feature = "acpi"))]
{
Err(())
}
};
match boot_info().platform_info {
PlatformInfo::LinuxBootParams { .. } => triple_fault(),
PlatformInfo::Multiboot { .. } => {
qemu_exit(error_code == 0);

#[cfg(feature = "acpi")]
{
acpi::poweroff();
}

match acpi_result {
Ok(_never) => unreachable!(),
Err(()) => {
match boot_info().platform_info {
PlatformInfo::LinuxBootParams { .. } => triple_fault(),
PlatformInfo::Multiboot { .. } => {
// Try QEMU's debug exit
let exit_handler = qemu_exit::X86::new(0xf4, 3);
if error_code == 0 {
exit_handler.exit_success()
} else {
exit_handler.exit_failure()
}
}
PlatformInfo::Uhyve { .. } => todo!(),
loop {
halt();
}
}
PlatformInfo::Uhyve { .. } => unreachable!(),
}
}

Expand Down
1 change: 1 addition & 0 deletions src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ pub(crate) fn get_application_parameters() -> (i32, *const *const u8, *const *co
pub(crate) fn shutdown(arg: i32) -> ! {
// print some performance statistics
crate::arch::kernel::print_statistics();
info!("shutting down with code {arg}");

SYS.shutdown(arg)
}
Expand Down
30 changes: 18 additions & 12 deletions xtask/src/ci/qemu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ impl Qemu {

thread::sleep(Duration::from_millis(100));
if let Some(status) = qemu.0.try_wait()? {
ensure!(status.qemu_success(), "QEMU exit code: {:?}", status.code());
ensure!(
self.qemu_success(status),
"QEMU exit code: {:?}",
status.code()
);
}

match self.build.package.as_str() {
Expand All @@ -107,7 +111,11 @@ impl Qemu {
let Some(status) = status else {
bail!("QEMU timeout")
};
ensure!(status.qemu_success(), "QEMU exit code: {:?}", status.code());
ensure!(
self.qemu_success(status),
"QEMU exit code: {:?}",
status.code()
);

if let Some(mut virtiofsd) = virtiofsd {
let status = virtiofsd.0.wait()?;
Expand Down Expand Up @@ -250,6 +258,14 @@ impl Qemu {
vec![]
}
}

fn qemu_success(&self, status: ExitStatus) -> bool {
if self.build.cargo_build.artifact.arch == Arch::X86_64 {
status.code() == Some(3)
} else {
status.success()
}
}
}

fn spawn_virtiofsd() -> Result<KillChildOnDrop> {
Expand Down Expand Up @@ -374,13 +390,3 @@ impl Drop for KillChildOnDrop {
self.0.kill().ok();
}
}

trait ExitStatusExt {
fn qemu_success(&self) -> bool;
}

impl ExitStatusExt for ExitStatus {
fn qemu_success(&self) -> bool {
self.success() || self.code() == Some(3)
}
}