Add support for reading hypervisor console (#344)

* feature(xencall): add hypervisor SYSCTL_readconsole definitions

* feature(hypervisor-dmesg): xencall: add read_console_ring_raw hypercall wrapper

* feature(hypervisor-dmesg): protobuf: add ReadHypervisorConsoleRing RPC

* feature(hypervisor-dmesg): runtime: add read_hypervisor_console wrapper

* feature(hypervisor-dmesg): daemon: add ReadHypervisorConsoleRing rpc implementation

* feature(hypervisor-dmesg): ctl: add host hypervisor-messages command to get hypervisor messages

* feature(hypervisor-dmesg): cli: rename hypervisor-messages command to hv-console

* feature(hypervisor-dmesg): proto: change ReadHypervisorConsoleRing to ReadHypervisorConsole

* feature(hypervisor-dmesg): fix up kratactl protobuf calls
This commit is contained in:
Ariadne Conill 2024-08-19 16:49:02 -07:00 committed by GitHub
parent 2519d76479
commit 2ab2cda937
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 118 additions and 2 deletions

View File

@ -0,0 +1,24 @@
use anyhow::Result;
use clap::Parser;
use krata::v1::control::{
control_service_client::ControlServiceClient, ReadHypervisorConsoleRequest,
};
use tonic::{transport::Channel, Request};
#[derive(Parser)]
#[command(about = "Display hypervisor diagnostic messages")]
pub struct HostHvConsoleCommand {
}
impl HostHvConsoleCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let response = client
.read_hypervisor_console(Request::new(ReadHypervisorConsoleRequest {}))
.await?
.into_inner();
print!("{}", response.data);
Ok(())
}
}

View File

@ -8,10 +8,12 @@ use krata::v1::control::control_service_client::ControlServiceClient;
use crate::cli::host::cpu_topology::HostCpuTopologyCommand; use crate::cli::host::cpu_topology::HostCpuTopologyCommand;
use crate::cli::host::identify::HostStatusCommand; use crate::cli::host::identify::HostStatusCommand;
use crate::cli::host::idm_snoop::HostIdmSnoopCommand; use crate::cli::host::idm_snoop::HostIdmSnoopCommand;
use crate::cli::host::hv_console::HostHvConsoleCommand;
pub mod cpu_topology; pub mod cpu_topology;
pub mod identify; pub mod identify;
pub mod idm_snoop; pub mod idm_snoop;
pub mod hv_console;
#[derive(Parser)] #[derive(Parser)]
#[command(about = "Manage the host of the isolation engine")] #[command(about = "Manage the host of the isolation engine")]
@ -35,6 +37,7 @@ pub enum HostCommands {
CpuTopology(HostCpuTopologyCommand), CpuTopology(HostCpuTopologyCommand),
Status(HostStatusCommand), Status(HostStatusCommand),
IdmSnoop(HostIdmSnoopCommand), IdmSnoop(HostIdmSnoopCommand),
HvConsole(HostHvConsoleCommand),
} }
impl HostCommands { impl HostCommands {
@ -49,6 +52,8 @@ impl HostCommands {
HostCommands::Status(status) => status.run(client).await, HostCommands::Status(status) => status.run(client).await,
HostCommands::IdmSnoop(snoop) => snoop.run(client, events).await, HostCommands::IdmSnoop(snoop) => snoop.run(client, events).await,
HostCommands::HvConsole(hvconsole) => hvconsole.run(client).await,
} }
} }
} }

View File

@ -28,6 +28,7 @@ use krata::{
ReadZoneMetricsReply, ReadZoneMetricsRequest, ResolveZoneIdReply, ResolveZoneIdRequest, ReadZoneMetricsReply, ReadZoneMetricsRequest, ResolveZoneIdReply, ResolveZoneIdRequest,
SnoopIdmReply, SnoopIdmRequest, UpdateZoneResourcesReply, UpdateZoneResourcesRequest, SnoopIdmReply, SnoopIdmRequest, UpdateZoneResourcesReply, UpdateZoneResourcesRequest,
WatchEventsReply, WatchEventsRequest, ZoneConsoleReply, ZoneConsoleRequest, WatchEventsReply, WatchEventsRequest, ZoneConsoleReply, ZoneConsoleRequest,
ReadHypervisorConsoleRequest, ReadHypervisorConsoleReply,
}, },
}, },
}; };
@ -710,4 +711,14 @@ impl ControlService for DaemonControlService {
.map_err(ApiError::from)?; .map_err(ApiError::from)?;
Ok(Response::new(UpdateZoneResourcesReply {})) Ok(Response::new(UpdateZoneResourcesReply {}))
} }
async fn read_hypervisor_console(
&self,
_request: Request<ReadHypervisorConsoleRequest>,
) -> Result<Response<ReadHypervisorConsoleReply>, Status> {
let data = self.runtime.read_hypervisor_console(false).await.map_err(|error| ApiError {
message: error.to_string(),
})?;
Ok(Response::new(ReadHypervisorConsoleReply { data: data.to_string() }))
}
} }

View File

@ -35,6 +35,8 @@ service ControlService {
rpc ReadZoneMetrics(ReadZoneMetricsRequest) returns (ReadZoneMetricsReply); rpc ReadZoneMetrics(ReadZoneMetricsRequest) returns (ReadZoneMetricsReply);
rpc WatchEvents(WatchEventsRequest) returns (stream WatchEventsReply); rpc WatchEvents(WatchEventsRequest) returns (stream WatchEventsReply);
rpc ReadHypervisorConsole(ReadHypervisorConsoleRequest) returns (ReadHypervisorConsoleReply);
} }
message HostStatusRequest {} message HostStatusRequest {}
@ -252,3 +254,9 @@ message UpdateZoneResourcesRequest {
} }
message UpdateZoneResourcesReply {} message UpdateZoneResourcesReply {}
message ReadHypervisorConsoleRequest {}
message ReadHypervisorConsoleReply {
string data = 1;
}

View File

@ -297,4 +297,14 @@ impl Runtime {
let context = RuntimeContext::new().await?; let context = RuntimeContext::new().await?;
Ok(PowerManagementContext { context }) Ok(PowerManagementContext { context })
} }
pub async fn read_hypervisor_console(&self, clear: bool) -> Result<Arc<str>> {
let index = 0 as u32;
let (rawbuf, newindex) = self.context
.xen
.call
.read_console_ring_raw(clear, index).await?;
let buf = std::str::from_utf8(&rawbuf[..newindex as usize])?;
Ok(Arc::from(buf))
}
} }

View File

@ -0,0 +1,18 @@
use xencall::error::Result;
use xencall::XenCall;
#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
let call = XenCall::open(0)?;
let index = 0 as u32;
let (buf, newindex) = call.read_console_ring_raw(false, index).await?;
match std::str::from_utf8(&buf[..newindex as usize]) {
Ok(v) => print!("{}", v),
_ => panic!("unable to decode Xen console messages"),
};
Ok(())
}

View File

@ -26,12 +26,12 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use sys::{ use sys::{
CpuId, E820Entry, ForeignMemoryMap, PhysdevMapPirq, Sysctl, SysctlCputopo, SysctlCputopoinfo, CpuId, E820Entry, ForeignMemoryMap, PhysdevMapPirq, Sysctl, SysctlCputopo, SysctlCputopoinfo,
SysctlPhysinfo, SysctlPmOp, SysctlPmOpValue, SysctlSetCpuFreqGov, SysctlValue, SysctlPhysinfo, SysctlPmOp, SysctlPmOpValue, SysctlSetCpuFreqGov, SysctlValue, SysctlReadconsole,
VcpuGuestContextAny, HYPERVISOR_PHYSDEV_OP, HYPERVISOR_SYSCTL, PHYSDEVOP_MAP_PIRQ, VcpuGuestContextAny, HYPERVISOR_PHYSDEV_OP, HYPERVISOR_SYSCTL, PHYSDEVOP_MAP_PIRQ,
XEN_DOMCTL_MAX_INTERFACE_VERSION, XEN_DOMCTL_MIN_INTERFACE_VERSION, XEN_MEM_SET_MEMORY_MAP, XEN_DOMCTL_MAX_INTERFACE_VERSION, XEN_DOMCTL_MIN_INTERFACE_VERSION, XEN_MEM_SET_MEMORY_MAP,
XEN_SYSCTL_CPUTOPOINFO, XEN_SYSCTL_MAX_INTERFACE_VERSION, XEN_SYSCTL_MIN_INTERFACE_VERSION, XEN_SYSCTL_CPUTOPOINFO, XEN_SYSCTL_MAX_INTERFACE_VERSION, XEN_SYSCTL_MIN_INTERFACE_VERSION,
XEN_SYSCTL_PHYSINFO, XEN_SYSCTL_PM_OP, XEN_SYSCTL_PM_OP_DISABLE_TURBO, XEN_SYSCTL_PHYSINFO, XEN_SYSCTL_PM_OP, XEN_SYSCTL_PM_OP_DISABLE_TURBO,
XEN_SYSCTL_PM_OP_ENABLE_TURBO, XEN_SYSCTL_PM_OP_SET_CPUFREQ_GOV, XEN_SYSCTL_PM_OP_ENABLE_TURBO, XEN_SYSCTL_PM_OP_SET_CPUFREQ_GOV, XEN_SYSCTL_READCONSOLE,
}; };
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use tokio::time::sleep; use tokio::time::sleep;
@ -1087,4 +1087,31 @@ impl XenCall {
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn read_console_ring_raw(&self, clear: bool, index: u32) -> Result<([u8; 16384], u32)> {
let mut u8buf = [0u8; 16384];
let mut sysctl = Sysctl {
cmd: XEN_SYSCTL_READCONSOLE,
interface_version: self.sysctl_interface_version,
value: SysctlValue {
console: SysctlReadconsole {
clear: clear as u8,
incremental: 1,
pad: 0,
index: index,
buffer: addr_of_mut!(u8buf) as u64,
count: 16384,
},
},
};
self.hypercall1(HYPERVISOR_SYSCTL, addr_of_mut!(sysctl) as c_ulong)
.await?;
// Safety: We are passing a SysctlReadconsole struct as part of the hypercall, and
// calling the hypercall is known to not change the underlying value outside changing
// the values on some SysctlReadconsole fields.
let newindex = unsafe {
sysctl.value.console.index
};
Ok((u8buf, newindex))
}
} }

View File

@ -752,6 +752,7 @@ pub struct SysctlCputopoinfo {
#[repr(C)] #[repr(C)]
pub union SysctlValue { pub union SysctlValue {
pub console: SysctlReadconsole,
pub cputopoinfo: SysctlCputopoinfo, pub cputopoinfo: SysctlCputopoinfo,
pub pm_op: SysctlPmOp, pub pm_op: SysctlPmOp,
pub phys_info: SysctlPhysinfo, pub phys_info: SysctlPhysinfo,
@ -765,6 +766,7 @@ pub struct Sysctl {
pub value: SysctlValue, pub value: SysctlValue,
} }
pub const XEN_SYSCTL_READCONSOLE: u32 = 1;
pub const XEN_SYSCTL_PHYSINFO: u32 = 3; pub const XEN_SYSCTL_PHYSINFO: u32 = 3;
pub const XEN_SYSCTL_PM_OP: u32 = 12; pub const XEN_SYSCTL_PM_OP: u32 = 12;
pub const XEN_SYSCTL_CPUTOPOINFO: u32 = 16; pub const XEN_SYSCTL_CPUTOPOINFO: u32 = 16;
@ -802,3 +804,14 @@ pub struct SysctlPhysinfo {
pub max_mfn: u64, pub max_mfn: u64,
pub hw_cap: [u32; 8], pub hw_cap: [u32; 8],
} }
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct SysctlReadconsole {
pub clear: u8,
pub incremental: u8,
pub pad: u16,
pub index: u32,
pub buffer: u64,
pub count: u32,
}